Let's Encrypt の certbotのエラー
Let's Encryptで証明書を発行しようとした時にハマったのでメモします。
証明書を発行するために、ドメインの認証をする必要があるのですが、いまは便利なものでcertbotという仕組みが用意されているようです。 検索すれば情報がたくさん出てきます。
さっそく私のCent7の環境でもcertbotで証明書を発行するべく、試してみましたが、ImportError: No module named contrib.pyopenssl
というエラーが出てしまいました。。。
[root@test foxtrot]# certbot certonly --webroot -w ~/cert -d example.jp Traceback (most recent call last): File "/bin/certbot", line 9, in <module> load_entry_point('certbot==0.19.0', 'console_scripts', 'certbot')() File "/usr/lib/python2.7/site-packages/pkg_resources.py", line 378, in load_entry_point return get_distribution(dist).load_entry_point(group, name) File "/usr/lib/python2.7/site-packages/pkg_resources.py", line 2566, in load_entry_point return ep.load() File "/usr/lib/python2.7/site-packages/pkg_resources.py", line 2260, in load entry = __import__(self.module_name, globals(),globals(), ['__name__']) File "/usr/lib/python2.7/site-packages/certbot/main.py", line 19, in <module> from certbot import client File "/usr/lib/python2.7/site-packages/certbot/client.py", line 11, in <module> from acme import client as acme_client File "/usr/lib/python2.7/site-packages/acme/client.py", line 33, in <module> import urllib3.contrib.pyopenssl # pylint: disable=import-error ImportError: No module named contrib.pyopenssl [root@test foxtrot]#
このエラーは、以下のようなissueを参考にしました。
何個か書かれていた手順をためしたり、パッケージをアップデートすることによって解決できました。
### pyOpenSSLのアップデート [root@test foxtrot]# rpm -Uvh pyOpenSSL-0.15.1-1.el7.noarch.rpm 準備しています... ################################# [100%] 更新中 / インストール中... 1:pyOpenSSL-0.15.1-1.el7 ################################# [ 50%] 整理中 / 削除中... 2:pyOpenSSL-0.13.1-3.el7 ################################# [100%] [root@test foxtrot]# ### シンボリックリンクの作成 [root@test foxtrot]# ln -s /usr/lib/python2.7/site-packages/OpenSSL /usr/lib/python2.7/site-packages/pyOpenSSL [root@test foxtrot]# [root@test foxtrot]# [root@test foxtrot]# ls -ld /usr/lib/python2.7/site-packages/pyOpenSSL lrwxrwxrwx 1 root root 40 11月 19 12:13 /usr/lib/python2.7/site-packages/pyOpenSSL -> /usr/lib/python2.7/site-packages/OpenSSL [root@test foxtrot]# ### python-urllibのアップデート [root@test foxtrot]# yum update python-urllib ... [root@test foxtrot]# rpm -qa | grep urllib python-urllib3-1.10.2-3.el7.noarch [root@test foxtrot]#
再度発行を試します。 この度は、調子よくメールアドレスとか聞いてきたのですが、また別のエラーが。。。 なんかのパッケージにバグがあるっぽいなと。。。
... Starting new HTTPS connection (1): acme-v01.api.letsencrypt.org An unexpected error occurred: TypeError: cannot concatenate 'str' and 'tuple' objects Please see the logfiles in /var/log/letsencrypt for more details.
どうしようかなーと考えて、再度検索し、結局別のcertbotをもってくることで解決しました。 参考にしたのは、gitのcertbotを持ってくる手順です。
これでなんとかかんとか証明書を発行することができました。 次は証明書の更新の自動化とかどうしようかなぁと考えています。
kernel メッセージのTaintedについて
kernelのメッセージが出た時にいつもNot taintedって出てましたが、このまえ、初めて、Taintedって出ていたのでメモしました。
これまでは、以下のようなNot taintedってメッセージ。Notって書いてあったのであまり気にしていませんでした。
Apr 22 16:48:27 dev001 kernel: Pid: 2429, comm: perl Not tainted 2.6.32-431.el6.x86_64 #1
それがこんな感じのメッセージ出ていたのでちょっとびっくり。
(Tainted: G W -- ------------ )
調べてみたところ、フラグの意味は以下のような感じみたいです。
/** * print_tainted - return a string to represent the kernel taint state. * * 'P' - Proprietary module has been loaded. * 'F' - Module has been forcibly loaded. * 'S' - SMP with CPUs not designed for SMP. * 'R' - User forced a module unload. * 'M' - System experienced a machine check exception. * 'B' - System has hit bad_page. * 'U' - Userspace-defined naughtiness. * 'D' - Kernel has oopsed before * 'A' - ACPI table overridden. * 'W' - Taint on warning. * 'C' - modules from drivers/staging are loaded. * 'I' - Working around severe firmware bug. * 'O' - Out-of-tree module has been loaded. * 'E' - Unsigned module has been loaded. * 'L' - A soft lockup has previously occurred. * 'K' - Kernel has been live patched. * * The string is overwritten by the next call to print_tainted(). */
http://askubuntu.com/questions/248470/what-does-the-kernel-taint-value-mean
あと、procからtaintedのstatusも確認できました。 何もなければ、0なのですが、warningが出ている状態だと、512が返ってきていました。
cat /proc/sys/kernel/tainted
statusの意味は以下のとおり。
tainted: Non-zero if the kernel has been tainted. Numeric values, which can be ORed together: 1 - A module with a non-GPL license has been loaded, this includes modules with no license. Set by modutils >= 2.4.9 and module-init-tools. 2 - A module was force loaded by insmod -f. Set by modutils >= 2.4.9 and module-init-tools. 4 - Unsafe SMP processors: SMP with CPUs not designed for SMP. 8 - A module was forcibly unloaded from the system by rmmod -f. 16 - A hardware machine check error occurred on the system. 32 - A bad page was discovered on the system. 64 - The user has asked that the system be marked "tainted". This could be because they are running software that directly modifies the hardware, or for other reasons. 128 - The system has died. 256 - The ACPI DSDT has been overridden with one supplied by the user instead of using the one provided by the hardware. 512 - A kernel warning has occurred. 1024 - A module from drivers/staging was loaded. 2048 - The system is working around a severe firmware bug. 4096 - An out-of-tree module has been loaded. 8192 - An unsigned module has been loaded in a kernel supporting module signature. 16384 - A soft lockup has previously occurred on the system. 32768 - The kernel has been live patched.
https://www.kernel.org/doc/Documentation/sysctl/kernel.txt
taintedという響きから嫌だなぁと思っていましたが、同じtaintedでも中身によって掘り下げれそうですね。
smapsみてみる
Linuxのメモリ周りをみていて、手元でもsmapsの内容を見てみました。 環境はkernel 3.10.0-229.el7.x86_64(バージョンアップしなきゃ。。)
実行したテストプログラムは以下のブログから丸々コピーさせてもらいました。
Linux のプロセスが Copy on Write で共有しているメモリのサイズを調べる - naoyaのはてなダイアリー
1回目がforkするだけのテストプログラムを動かした結果で、 2回目が、ブログにあるとおり、コメントアウトを外して、fork & 書き込みまでおこなった結果です。 ほぼ参考にさせて頂いたブログにあるとおりの結果になっていました。
# 1回目 00602000-067aa000 rw-p 00000000 00:00 0 Size: 100000 kB Rss: 100000 kB Pss: 50000 kB Shared_Clean: 0 kB Shared_Dirty: 100000 kB Private_Clean: 0 kB Private_Dirty: 0 kB Referenced: 100000 kB Anonymous: 100000 kB AnonHugePages: 96256 kB Swap: 0 kB KernelPageSize: 4 kB MMUPageSize: 4 kB Locked: 0 kB VmFlags: rd wr mr mw me ac
#2回目 00602000-067aa000 rw-p 00000000 00:00 0 Size: 100000 kB Rss: 100000 kB Pss: 75596 kB Shared_Clean: 0 kB Shared_Dirty: 48808 kB Private_Clean: 0 kB Private_Dirty: 51192 kB Referenced: 100000 kB Anonymous: 100000 kB AnonHugePages: 96256 kB Swap: 0 kB KernelPageSize: 4 kB MMUPageSize: 4 kB Locked: 0 kB VmFlags: rd wr mr mw me ac
このPssなる項目は、proportional set sizeというものらしいです。 以下のサイトに例がのっていてなんとなくわかったような気になりました。(実際はメモリ周りの扱いがわかっていないので、わかっていない。。。)
The "proportional set size" (PSS) of a process is the count of pages it has in memory, where each page is divided by the number of processes sharing it. So if a process has 1000 pages all to itself, and 1000 shared with one other process, its PSS will be 1500.
https://www.kernel.org/doc/Documentation/filesystems/proc.txt
今回のテストの場合もprivateとsharedが1:1なので、PSSの値もほぼ上記の例と同じ比率になっているような気がします。
詳しくはまたどこかで調べてみます。
dirname()とbasename()の挙動の確認
現在、社内の人と勉強会をしているLinuxProgramingInterfaceにて出て来たdirname()とbasename()の挙動について、実際に確認してみました。
18章に以下のような文言がありました。
dirname() と basename() はいずれも pathname の文字列を変更する可能性があります。 このため、pathname を再度利用する場合は、例 18-5 に挙げるようにコピーを作成し、コピーを dirname()、basename() へ渡します。
ここでいうpathnameはdirname() or basename()に与える/xxx/yyyみたいなやつです。
上記がどういうことかと教えてもらったところ、両関数は与えられた文字列を直接書き換えちゃうので、もっかい文字列を参照したい場合はコピーした文字列を両関数に渡してねってことらしいです。
本当に文字列を書き換えてしまうのか確認してみました。
使用したソースコードは、LinuxProgramingInterfaceの中に出て行きた例18-5です。
http://man7.org/tlpi/code/online/dist/dirs_links/t_dirbasename.c.html
gdbで見てみます。
下記は、行数の確認 & 引数の指定 & 引数の確認 & ブレイクポイントの設定です。
(gdb) list 23 #include <libgen.h> 24 #include "tlpi_hdr.h" 25 26 int 27 main(int argc, char *argv[]) 28 { 29 char *t1, *t2; 30 int j; 31 32 for (j = 1; j < argc; j++) { (gdb) set args /dirname/filename (gdb) show args Argument list to give program being debugged when it is started is "/dirname/filename". (gdb) b 30
実行!
与える文字列は/dirname/filename
としました。
文字列をt1,t2にコピーして、中身を確認します。
この時点ではt1,t2ともに/dirname/filename
のままみたいです。
(gdb) r Starting program: /xxxx/t_dirbasename /dirname/filename Breakpoint 1, main (argc=2, argv=0x7fffffffe648) at t_dirbasename.c:32 32 for (j = 1; j < argc; j++) { (gdb) n 33 t1 = strdup(argv[j]); (gdb) n 34 if (t1 == NULL) (gdb) n 36 t2 = strdup(argv[j]); (gdb) n 37 if (t2 == NULL) (gdb) n 40 printf("%s ==> %s + %s\n", argv[j], dirname(t1), basename(t2)); (gdb) p t1 $1 = 0x603010 "/dirname/filename" (gdb) p t2 $2 = 0x603030 "/dirname/filename" (gdb) p *t1 $3 = 47 '/' (gdb) p *t2 $4 = 47 '/' (gdb) p *(t1+1) $5 = 100 'd' (gdb) p *(t1+2) $6 = 105 'i' (gdb) p *(t1+3) $7 = 114 'r' (gdb) p *(t1+4) $8 = 110 'n' (gdb) p *(t1+5) $9 = 97 'a' (gdb) p *(t1+6) $10 = 109 'm' (gdb) p *(t1+7) $11 = 101 'e' (gdb) p *(t1+8) $12 = 47 '/' (gdb) p *(t1+9) $13 = 102 'f'
さて、問題のdirname(),basename()の実行。
確かにt1は/dirname
になり、t2は/dirname/filename
になりました。
着目すべきは*(t1+8)が /
ではなく、\000
に書き換えられているところですね!
だからt1が/dirname
になるんですね〜。
(gdb) n /dirname/filename ==> /dirname + filename 42 free(t1); (gdb) p t1 $14 = 0x603010 "/dirname" (gdb) p t2 $15 = 0x603030 "/dirname/filename" (gdb) p *t1 $16 = 47 '/' (gdb) p *t2 $17 = 47 '/' (gdb) p *(t1+8) $18 = 0 '\000' (gdb) p *(t1+9) $19 = 102 'f'
もちろん、p t1+9は、filename
になりました。
(gdb) p *(t2+1) $20 = 100 'd' (gdb) p t1+9 $21 = 0x603019 "filename" (gdb) quit
以上、確認終わり!
gdbでスタックフレームを見てみる
最近Linuxプログラミングインターフェースの輪読をおこなっているので、その復習のため、ちょっと見てみました。
こんなソースを実行。 allocaはおまけです。
1 #include <stdio.h> 2 #include <alloca.h> 3 4 void test1(int *); 5 void test2(int *); 6 void test3(int *); 7 8 int main(int argc, char *argv) { 9 int a = 111; 10 test1(&a); 11 return 0; 12 } 13 14 void test1(int *a){ 15 printf("test1 : %d\n",*a); 16 printf("test1 address : %p\n",test1); 17 test2(a); 18 } 19 20 void test2(int *a){ 21 *a = 222; 22 void *x; 23 printf("test2 : %d\n",*a); 24 printf("test2 address : %p\n",test2); 25 x = alloca(4); 26 printf("alloca : %p\n",x); 27 test3(a); 28 } 29 30 void test3(int *a){ 31 *a = 333; 32 printf("test3 : %d\n",*a); 33 printf("test3 address : %p\n",test3); 34 }
gdbでdebugしてみる。 break pointの設定 && 実行
(gdb) break 34 Breakpoint 1 at 0x400678: file ./stack_test.c, line 34. (gdb) run Starting program: /home/foxtrot/stack_test/./a.out test1 : 111 test1 address : 0x400559 test2 : 222 test2 address : 0x40059e alloca : 0x7fffffffe510 test3 : 333 test3 address : 0x400637 Breakpoint 1, test3 (a=0x7fffffffe59c) at ./stack_test.c:34 34 } (gdb)
backtrace! 先頭からプログラムカウンタの値、関数名、引数、コードの実行箇所みたいです。
(gdb) backtrace #0 test3 (a=0x7fffffffe59c) at ./stack_test.c:34 #1 0x0000000000400635 in test2 (a=0x7fffffffe59c) at ./stack_test.c:27 #2 0x000000000040059c in test1 (a=0x7fffffffe59c) at ./stack_test.c:17 #3 0x0000000000400552 in main (argc=1, argv=0x7fffffffe688 "\253\350\377\377\377\177") at ./stack_test.c:10
frame 数字 を指定することで、実行しているソースコードの場所も見れます。 このときlistを実行することで、さらにその周りのソースコードも見れるとか。
(gdb) frame 1 #1 0x0000000000400635 in test2 (a=0x7fffffffe59c) at ./stack_test.c:27 27 test3(a); (gdb) list 22 void *x; 23 printf("test2 : %d\n",*a); 24 printf("test2 address : %p\n",test2); 25 x = alloca(4); 26 printf("alloca : %p\n",x); 27 test3(a); 28 } 29 30 void test3(int *a){ 31 *a = 333;
info localsでローカル変数。info argsで引数
(gdb) info args a = 0x7fffffffe59c (gdb) info locals x = 0x7fffffffe510
info frame 数字 でより詳しい情報がみれます。 呼び出し元とか呼び出し先とかプログラムカウンタの値とか。
(gdb) info frame 0 Stack frame at 0x7fffffffe510: rip = 0x400678 in test3 (./stack_test.c:34); saved rip 0x400635 called by frame at 0x7fffffffe560 source language c. Arglist at 0x7fffffffe500, args: a=0x7fffffffe59c Locals at 0x7fffffffe500, Previous frame's sp is 0x7fffffffe510 Saved registers: rbp at 0x7fffffffe500, rip at 0x7fffffffe508 (gdb) info frame 1 Stack frame at 0x7fffffffe560: rip = 0x400635 in test2 (./stack_test.c:27); saved rip 0x40059c called by frame at 0x7fffffffe580, caller of frame at 0x7fffffffe510 source language c. Arglist at 0x7fffffffe550, args: a=0x7fffffffe59c Locals at 0x7fffffffe550, Previous frame's sp is 0x7fffffffe560 Saved registers: rbp at 0x7fffffffe550, rip at 0x7fffffffe558 (gdb) info frame 2 Stack frame at 0x7fffffffe580: rip = 0x40059c in test1 (./stack_test.c:17); saved rip 0x400552 called by frame at 0x7fffffffe5b0, caller of frame at 0x7fffffffe560 source language c. Arglist at 0x7fffffffe570, args: a=0x7fffffffe59c Locals at 0x7fffffffe570, Previous frame's sp is 0x7fffffffe580 Saved registers: rbp at 0x7fffffffe570, rip at 0x7fffffffe578 (gdb) info frame 3 Stack frame at 0x7fffffffe5b0: rip = 0x400552 in main (./stack_test.c:10); saved rip 0x7ffff7a3bb15 caller of frame at 0x7fffffffe580 source language c. Arglist at 0x7fffffffe5a0, args: argc=1, argv=0x7fffffffe688 "\253\350\377\377\377\177" Locals at 0x7fffffffe5a0, Previous frame's sp is 0x7fffffffe5b0 Saved registers: rbp at 0x7fffffffe5a0, rip at 0x7fffffffe5a8
Stack frame at xxxxの箇所が、Stackのメモリアドレスなのかな。 試しにallocaに大きな値を入れてみた。
25 x = alloca(64);
これでgdbで再度見てみると確かに値が変わっている! 前回はframe 0の値が「Stack frame at 0x7fffffffe510:」だったけれども、今回は「Stack frame at 0x7fffffffe4e0:」になっている。
(gdb) info frame 0 Stack frame at 0x7fffffffe4e0: rip = 0x4006c2 in test3 (./stack_test.c:37); saved rip 0x400635 called by frame at 0x7fffffffe560 source language c. Arglist at 0x7fffffffe4d0, args: a=0x7fffffffe59c Locals at 0x7fffffffe4d0, Previous frame's sp is 0x7fffffffe4e0 Saved registers: rbp at 0x7fffffffe4d0, rip at 0x7fffffffe4d8 (gdb) info frame 1 Stack frame at 0x7fffffffe560: rip = 0x400635 in test2 (./stack_test.c:27); saved rip 0x40059c called by frame at 0x7fffffffe580, caller of frame at 0x7fffffffe4e0 source language c. Arglist at 0x7fffffffe550, args: a=0x7fffffffe59c Locals at 0x7fffffffe550, Previous frame's sp is 0x7fffffffe560 Saved registers: rbp at 0x7fffffffe550, rip at 0x7fffffffe558
ripとかは退避したプログラムカウンタの値?ripはeipの64bit版なんですかね。。 なんか調べると奥が深そうだから、また今度!
lldbコマンドの使い方
もう完全に忘れていたので、メモ!
gcc -g ./test.c
こんな感じで起動
lldb ./a.out
listでソースコードをみれる。breakpointを設定したい行番号を確認。
(lldb) list 7 int main(void){ 8 int a,b,i=0,j=0; 9 int checkresult; 10 char tmp[5]; ...
ちなみにenterをおしたら前と同じコマンドの繰り返し。
breakpointを設定。breakpointの"b"と"ソースコードのファイル名":"行番号"
(lldb) b test.c:25
breakpointを設定後、rで実行。
(lldb) r Process 2604 launched: './a.out' (x86_64)
sで1行ずつ実行。nでも進む。nだと関数とかは飛ばしてくれる。
(lldb) s 23 M[j][strlen(M[j]) - 1] = '\0'; 24 } 25 for(i=0;i<a;i++){ -> 26 for(j=0;j<a;j++){
"print 変数名"で実行しているタイミングの変数の値が確認できる
(lldb) print i (int) $6 = 0 (lldb) print N[0] (char [201]) $8 = "0000"
なんかちょっとポインタの勉強になっておもしろい。
(lldb) print N (char (*)[201]) $10 = 0x00007fff5fbf5c78 (lldb) print *N (char [201]) $11 = "0000" (lldb) print *N[0] (char) $12 = '0'
quitでおしまい。
(lldb) quit Quitting LLDB will kill one or more processes. Do you really want to proceed: [Y/n] Y
ファイルへの追記のみを可能にする方法
知らなかったので、メモ。 logファイルの改ざん防止とか良さそう。
準備。lsattrで現在のファイルの属性をみれる。
[root@test foxtrot]# touch addonly.txt [root@test foxtrot]# [root@test foxtrot]# lsattr addonly.txt -------------e- addonly.txt [root@test foxtrot]# [root@test foxtrot]# echo "first" > addonly.txt [root@test foxtrot]# [root@test foxtrot]# cat addonly.txt first [root@test foxtrot]#
追加のみ許可の属性を付与。 上書きしたら、メッセージが表示されてエラー。 追記はOK!
[root@test foxtrot]# chattr +a addonly.txt [root@test foxtrot]# [root@test foxtrot]# lsattr addonly.txt -----a-------e- addonly.txt [root@test foxtrot]# [root@test foxtrot]# echo "second" > addonly.txt bash: addonly.txt: 許可されていない操作です [root@test foxtrot]# [root@test foxtrot]# echo "second" >> addonly.txt [root@test foxtrot]# [root@test foxtrot]# cat addonly.txt first second
まぁ、logファイルを改ざんできるぐらいなら、、、とかも思うけど。