显示标签为“linux”的博文。显示所有博文
显示标签为“linux”的博文。显示所有博文

2013年8月13日星期二

Google安全团队对Android安全的认识

看看google的攻城师对android安全的认识:
1、敏感数据通过权限保护,这些权限都会由权贵把持,要想使用就得申请。
2、码农的安全意识很重要
码农很努力了,可惜由于缺乏安全意识,可能导致数据泄露:
- Storing personal data in a world-readable  file 全局读文件。。。
- Exporting an unprotected content provider  组件导出,人人都可以访问。组件导出,容易被人滥用,造成权限代理攻击。
- Logging personal data in logcat logs           喜欢log。。
还要考虑邪恶的外部环境啊
- Insecure wireless networks  传输容易被窃取,最近连ssl都被人攻破了
- Lost and stolen devices 丢手机
3、用户证书
随便android 没有ios那样有严格的开发者证书,自己随便玩证书。但也要严肃点。
毕竟证书承载了不少内容。
1)、同样的签名可以共用UID
2)、软件升级的问题。
因此,为了安全起见,程序猿也要保护好自己的私钥!!!要不然被人窃取了,他可能会窃取你的应用信息哦。
4、android安全架构
android的安全架构主要有这样几部分:
1)、linux DAC机制,也就是RWX,还有些特殊的组ID控制,比如internet
比如open()都是kernel通过uid控制
2)、组件认证,通常是被调用的一方进行权限控制,比如调用系统能力可能有System_server鉴权,如果和另一个应用交互,那就由另一个应用鉴权。其实就是IPC认证
5、沙箱
应用都是存在于自己的沙箱。
但也要考虑2个问题:
1)、反射的问题,现在很多hook的技术最后都是通过反射和java层对接。很邪恶
2)、native code不是法外之地,无法绕开permission机制,但可以修改进程空间,也就是动态修改应用状态。
另外进程间通信也有一些保护手段:
Intent filters---过滤而已
Permissions---就是摆设
Signatures-----真的有价值。共享签名的价值。
6、攻击入口
7、保护组件
Don't export app components unless you want other apps on the system to interact with your app
manifest xmlns:android="http://schemas.android.com/apk/res/android "
          package="com.example.awesome">
    <application android:label="@string/app_name">
        …
        <service android:name=".ServiceExample"
                 android:exported="false">
            <intent-filter>…</intent-filter>
        </service>
        …
    </application>
</manifest>
万不得已,不要到处。实在要到处,请下申请权限,而后共享签名控制(下面的最后一种)!!血泪教训
定义权限只是万里长征第一步,你定义了,别人申请即可,关键得签名控制!
protectionLevel="normal"  – A lower-risk permission that gives requesting applications
access to isolated application-level features, with minimal risk to other applications, the
system, or the user. This is the default protection level.            悄悄地干活,啥都不提示

protectionLevel="dangerous"   – A higher-risk permission that would give a requesting
application access to private user data or control over the device that can negatively impact
the user.                 就是提示,有啥用
protectionLevel="signature"  – Can be used to limit access to components to only apps
signed with the same certificate.             真正有价值的!

上述的权限控制都是你定义了,系统帮你控制验证,你自己也可以的,要自信点。
其实很多种方法(下面列的太少了)
- Context.registerReceiver(…)  can be used to register a BroadcastReceiver dynamically
• There is a version of  registerReceiver(…)  which can be used to specify permission the broadcaster must hold for your dynamically-registered receiver to be invoked.
- Context.checkCallingPermission(…) and  Context.enforceCallingPermission(…) can be  自己验证
used in your source code to make sure the calling app holds the appropriate permission.
 This can be used to implement  fine-grained permissions if needed.

• Avoid the  confused deputy problem:权限代理的问题,我申请了一个专利,也有学术界的论文提出解决防范,很简单就是一个 ∩!!!
下图说了,不申请权限要玩没门!!但申请了权限容易被一些屌丝杀软发现啊!!!肿么办!!

- If your app is using its granted permissions to respond to another app, check that the calling app has that permission as well

那就找有这些权限的,同时有漏洞的。。就是提供接口的。。。
8、注意细节啊
1)debug
android:debuggable   不要开启啊!!容易被人***
- Disabled by default
- Never leave this enabled in release code!
- Allows a user to debug your app - even without source code
- Users with physical access can run code as your app and access your app's data  开启你的隐私之旅。。。run-as有不懂的吗?
jlarimer-macbookair:~ jlarimer$ adb shell
shell@android:/ $ run-as com.example.awesomeness sh
shell@android:/data/data/com.example.awesomeness $ id
uid=10060(app_60) gid=10060(app_60)
shell@android:/data/data/com.example.awesomeness $ ls files/
secret_data.txt
shell@android:/data/data/com.example.awesomeness $ cat files/secret_data.txt
SECRETS!
2)、数据
Use MODE_PRIVATE for data files, shared preferences, and databases  保护自己的隐私,别全局读写啊
• openFileOutput(),   openSharedPreferences(),  and  openOrCreateDatabase() create  files in your app's
private data directory
External storage (sdcard) is shared storage     sd卡没有权限控制,都可以读取,要存储三思啊,不行就加密啊!现在有很多开源加密库!
encryptedMessage = Encrypt(K, "Login-OK=0")
AlteredMessage = EncryptedMessage … XOR {…,0x31}
Plaintext = Decrypt(K, AlteredMessage) = "Login-OK=1"
好码农
FileOutputStream fos = openFileOutput("private_data.txt", Context.MODE_PRIVATE);
SharedPreferences prefs = getSharedPreferences("data", Context.MODE_PRIVATE);
女神对任何人都是开放的!
FileOutputStream fos = openFileOutput("private_data.txt", Context.MODE_WORLD_WRITEABL
SharedPreferences prefs = getSharedPreferences("data", Context.MODE_WORLD_READABLE);
sd卡里面也不要存储程序哦:
Don't store code libraries that are world writable or on external storage 容易被替换,除非你校验
- Don't store paths to code libraries in files that are world writable or on external storage  路径也一样
- Don't process data from writable files in native code - memory corruption vulnerabilities could allow apps to run arbitrary code with your app's ID  C语言爱溢出啊!!
• Don't store personal or protected data on external storage without user consent
9、无线链路的安全
现在屌丝太多,就喜欢在星巴克搞WIFI Hack。
很多中间人攻击手段!
如何防护:

- HTTPS and SSL can protect against MitM attacks and prevent casual snooping  用https和ssl啊。但现在ssl在码农实现时存在太多的问题,详情看老王的书吧!比如Certificate pinning
-比如
URL url = new URL("https://www.google.com/ ");
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
友情提示:
   Use cryptographic signing for any DEX or native code libraries that you load dynamically  这都是邪恶的软件才干的!远程下载APK、dex动态执行的
- Better yet, don't run code from the network
10、webview
 web的安全话题就大了。。。xss.....
webview 中JavaScript is disabled by default。缺省是禁止的
addJavascriptInterface() is dangerous 你可以启用的。
- Avoid exposing protected or personal data to a JavaScript interface   既然放开了,就很难保证了,js和java就可以通信了,同时同源机制会被破坏。
- Server or network could be compromised, you can't trust the code
- If you do use it, ensure that you're using HTTPS for the WebView
10、友情提示
   不要滥用职权,人民不会宽恕的!!申请最小的权利即可!

Permissions aren't required if you launch an activity that has the permission 系统已有task了,就别再申请权限了,直接调用这些应用即可!google为啥不直接删除那些直接发短信的api。谁能告诉我!!!
- Getting a picture from the camera
// create Intent to take a picture and return control to the calling application没权限照样干!!
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// create a file to save the image
fileUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE);
// set the image file name
intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
// start the image capture Intent
startActivityForResult(intent, MY_REQUEST_CO

- Sending an SMS through the SMS app  没权照样发!!

Uri smsNumber = Uri.parse("sms:5551212");
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(smsNumber);
intent.putExtra(Intent.EXTRA_TEXT, "hey there!");
startActivity(intent);
Permissions can be temporarily granted to apps by content providers 
- Letting the user pick a contact to share with your app           无需申请READ_CONTACTS啊!!
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType(Phone.CONTENT_ITEM_TYPE);
startActivityForResult(intent, MY_REQUEST_CODE);
void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (data != null) {
        Uri uri = data.getData();
        if (uri != null) {
            try {
                Cursor c = getContentResolver().query(uri, new String[] {
                    Contacts.DISPLAY_NAME, Phone.NUMBER}, null, null, null);
11、trick
Need a unique identifier?   唯一标示终端靠啥!老衲找了很多年,没找到!!下面的这些就更不靠谱了!
- TelephonyManager.getDeviceId() requires  READ_PHONE_STATE  permission
- Settings.Secure.ANDROID_ID doesn't require a permission, but still not perfect
To identify an installation of your app
- Generate a UUID when your app starts and store it in shared preferences:
- String id = UUID.randomUUID().toString();
- Use Android Backup Service to save the shared preferences to the cloud
- See: https://developers.google.com/android/backup/ 
12、设备管理
      设备管理本来是为企业管理MDM而生,可竟然被一些宵小用来作恶!!
最近史上最牛的恶意软件也用了设备管理,而后利用一个注册漏洞,竟然藏起来了。。让用户无法卸载这儿妖孽!!!
企业管理器激活后有很多功能,可以设置pin码复杂度,锁屏,擦出数据等等,ios的这部分就更丰富了!!
大家可以自己体验一下,激活后可以去激活!有个漏洞就是没有显示在激活列表。不去激活的话,应用是无法卸载的!于是成了邪恶!

最后
Use Android Lint  希望google 更加努力。让程序猿更多的时间和女神在一起!不要纠结在bug上!但现在的功能太小儿科!

这个功能很有商机!!有投资者看到了请与我联系。我做了应用漏洞检测工具!

Linux中如何让进程在后台运行

在Linux中,如果要让进程在后台运行,一般情况下,我们在命令后面加上&即可,实际上,这样是将命令放入到一个作业队列中了:
$ ./test.sh &
[1] 17208

$ jobs -l
[1]+ 17208 Running                 ./test.sh &
对于已经在前台执行的命令,也可以重新放到后台执行,首先按ctrl+z暂停已经运行的进程,然后使用bg命令将停止的作业放到后台运行:
$ ./test.sh
[1]+  Stopped                 ./test.sh

$ bg %1
[1]+ ./test.sh &

$ jobs -l
[1]+ 22794 Running                 ./test.sh &
但是如上方到后台执行的进程,其父进程还是当前终端shell的进程,而一旦父进程退出,则会发送hangup信号给所有子进程,子进程收到hangup以后也会退出。如果我们要在退出shell的时候继续运行进程,则需要使用nohup忽略hangup信号,或者setsid将将父进程设为init进程(进程号为1)
$ echo $$
21734

$ nohup ./test.sh &
[1] 29016

$ ps -ef | grep test
515      29710 21734  0 11:47 pts/12   00:00:00 /bin/sh ./test.sh
515      29713 21734  0 11:47 pts/12   00:00:00 grep test
$ setsid ./test.sh &
[1] 409

$ ps -ef | grep test
515        410     1  0 11:49 ?        00:00:00 /bin/sh ./test.sh
515        413 21734  0 11:49 pts/12   00:00:00 grep test
上面的试验演示了使用nohup/setsid加上&使进程在后台运行,同时不受当前shell退出的影响。那么对于已经在后台运行的进程,该怎么办呢?可以使用disown命令:
$ ./test.sh &
[1] 2539

$ jobs -l
[1]+  2539 Running                 ./test.sh &

$ disown -h %1

$ ps -ef | grep test
515        410     1  0 11:49 ?        00:00:00 /bin/sh ./test.sh
515       2542 21734  0 11:52 pts/12   00:00:00 grep test
另外还有一种方法,即使将进程在一个subshell中执行,其实这和setsid异曲同工。方法很简单,将命令用括号() 括起来即可:
$ (./test.sh &)

$ ps -ef | grep test
515        410     1  0 11:49 ?        00:00:00 /bin/sh ./test.sh
515      12483 21734  0 11:59 pts/12   00:00:00 grep test
注:本文试验环境为Red Hat Enterprise Linux AS release 4 (Nahant Update 5),shell为/bin/bash,不同的OS和shell可能命令有些不一样。例如AIX的ksh,没有disown,但是可以使用nohup -p PID来获得disown同样的效果。
还有一种更加强大的方式是使用screen,首先创建一个断开模式的虚拟终端,然后用-r选项重新连接这个虚拟终端,在其中执行的任何命令,都能达到nohup的效果,这在有多个命令需要在后台连续执行的时候比较方便:
$ screen -dmS screen_test

$ screen -list
There is a screen on:
        27963.screen_test       (Detached)
1 Socket in /tmp/uscreens/S-jiangfeng.

$ screen -r screen_test

Linux 技巧:让进程在后台可靠运行的几种方法

我们经常会碰到这样的问题,用 telnet/ssh 登录了远程的 Linux 服务器,运行了一些耗时较长的任务, 结果却由于网络的不稳定导致任务中途失败。如何让命令提交后不受本地关闭终端窗口/网络断开连接的干扰呢?下面举了一些例子, 您可以针对不同的场景选择不同的方式来处理这个问题。
如果只是临时有一个命令需要长时间运行,什么方法能最简便的保证它在后台稳定运行呢?

hangup 名称的来由

在 Unix 的早期版本中,每个终端都会通过 modem 和系统通讯。当用户 logout 时,modem 就会挂断(hang up)电话。 同理,当 modem 断开连接时,就会给终端发送 hangup 信号来通知其关闭所有子进程。
我们知道,当用户注销(logout)或者网络断开时,终端会收到 HUP(hangup)信号从而关闭其所有子进程。因此,我们的解决办法就有两种途径:要么让进程忽略 HUP 信号,要么让进程运行在新的会话里从而成为不属于此终端的子进程。
1. nohup
nohup 无疑是我们首先想到的办法。顾名思义,nohup 的用途就是让提交的命令忽略 hangup 信号。让我们先来看一下 nohup 的帮助信息:
NOHUP(1)                        User Commands                        NOHUP(1)

NAME
       nohup - run a command immune to hangups, with output to a non-tty

SYNOPSIS
       nohup COMMAND [ARG]...
       nohup OPTION

DESCRIPTION
       Run COMMAND, ignoring hangup signals.

       --help display this help and exit

       --version
              output version information and exit 

可见,nohup 的使用是十分方便的,只需在要处理的命令前加上 nohup 即可,标准输出和标准错误缺省会被重定向到 nohup.out 文件中。一般我们可在结尾加上"&"来将命令同时放入后台运行,也可用">filename 2>&1"来更改缺省的重定向文件名。

nohup 示例
                
[root@pvcent107 ~]# nohup ping www.ibm.com &
[1] 3059
nohup: appending output to `nohup.out'
[root@pvcent107 ~]# ps -ef |grep 3059
root      3059   984  0 21:06 pts/3    00:00:00 ping www.ibm.com
root      3067   984  0 21:06 pts/3    00:00:00 grep 3059
[root@pvcent107 ~]#  

2。setsid
nohup 无疑能通过忽略 HUP 信号来使我们的进程避免中途被中断,但如果我们换个角度思考,如果我们的进程不属于接受 HUP 信号的终端的子进程,那么自然也就不会受到 HUP 信号的影响了。setsid 就能帮助我们做到这一点。让我们先来看一下 setsid 的帮助信息:
SETSID(8)                 Linux Programmer’s Manual                 SETSID(8)

NAME
       setsid - run a program in a new session

SYNOPSIS
       setsid program [ arg ... ]

DESCRIPTION
       setsid runs a program in a new session. 

可见 setsid 的使用也是非常方便的,也只需在要处理的命令前加上 setsid 即可。

setsid 示例
                
[root@pvcent107 ~]# setsid ping www.ibm.com
[root@pvcent107 ~]# ps -ef |grep www.ibm.com
root     31094     1  0 07:28 ?        00:00:00 ping www.ibm.com
root     31102 29217  0 07:29 pts/4    00:00:00 grep www.ibm.com
[root@pvcent107 ~]#   

值得注意的是,上例中我们的进程 ID(PID)为31094,而它的父 ID(PPID)为1(即为 init 进程 ID),并不是当前终端的进程 ID。请将此例与nohup 例中的父 ID 做比较。
3。&
这里还有一个关于 subshell 的小技巧。我们知道,将一个或多个命名包含在“()”中就能让这些命令在子 shell 中运行中,从而扩展出很多有趣的功能,我们现在要讨论的就是其中之一。
当我们将"&"也放入“()”内之后,我们就会发现所提交的作业并不在作业列表中,也就是说,是无法通过jobs来查看的。让我们来看看为什么这样就能躲过 HUP 信号的影响吧。

subshell 示例
                
[root@pvcent107 ~]# (ping www.ibm.com &)
[root@pvcent107 ~]# ps -ef |grep www.ibm.com
root     16270     1  0 14:13 pts/4    00:00:00 ping www.ibm.com
root     16278 15362  0 14:13 pts/4    00:00:00 grep www.ibm.com
[root@pvcent107 ~]#   

从上例中可以看出,新提交的进程的父 ID(PPID)为1(init 进程的 PID),并不是当前终端的进程 ID。因此并不属于当前终端的子进程,从而也就不会受到当前终端的 HUP 信号的影响了。
我们已经知道,如果事先在命令前加上 nohup 或者 setsid 就可以避免 HUP 信号的影响。但是如果我们未加任何处理就已经提交了命令,该如何补救才能让它避免 HUP 信号的影响呢?
这时想加 nohup 或者 setsid 已经为时已晚,只能通过作业调度和 disown 来解决这个问题了。让我们来看一下 disown 的帮助信息:
disown [-ar] [-h] [jobspec ...]
 Without options, each jobspec is  removed  from  the  table  of
 active  jobs.   If  the -h option is given, each jobspec is not
 removed from the table, but is marked so  that  SIGHUP  is  not
 sent  to the job if the shell receives a SIGHUP.  If no jobspec
 is present, and neither the -a nor the -r option  is  supplied,
 the  current  job  is  used.  If no jobspec is supplied, the -a
 option means to remove or mark all jobs; the -r option  without
 a  jobspec  argument  restricts operation to running jobs.  The
 return value is 0 unless a jobspec does  not  specify  a  valid
 job.

可以看出,我们可以用如下方式来达成我们的目的。

灵活运用 CTRL-z

在我们的日常工作中,我们可以用 CTRL-z 来将当前进程挂起到后台暂停运行,执行一些别的操作,然后再用 fg 来将挂起的进程重新放回前台(也可用 bg 来将挂起的进程放在后台)继续运行。这样我们就可以在一个终端内灵活切换运行多个任务,这一点在调试代码时尤为有用。因为将代码编辑器挂起到后台再重新放回时,光标定位仍然停留在上次挂起时的位置,避免了重新定位的麻烦。
  • disown -h jobspec 来使某个作业忽略HUP信号。
  • disown -ah 来使所有的作业都忽略HUP信号。
  • disown -rh 来使正在运行的作业忽略HUP信号。
需要注意的是,当使用过 disown 之后,会将把目标作业从作业列表中移除,我们将不能再使用jobs来查看它,但是依然能够用ps -ef查找到它。
但是还有一个问题,这种方法的操作对象是作业,如果我们在运行命令时在结尾加了"&"来使它成为一个作业并在后台运行,那么就万事大吉了,我们可以通过jobs命令来得到所有作业的列表。但是如果并没有把当前命令作为作业来运行,如何才能得到它的作业号呢?答案就是用 CTRL-z(按住Ctrl键的同时按住z键)了!
CTRL-z 的用途就是将当前进程挂起(Suspend),然后我们就可以用jobs命令来查询它的作业号,再用bg jobspec 来将它放入后台并继续运行。需要注意的是,如果挂起会影响当前进程的运行结果,请慎用此方法。

disown 示例1(如果提交命令时已经用“&”将命令放入后台运行,则可以直接使用“disown”)
                
[root@pvcent107 build]# cp -r testLargeFile largeFile &
[1] 4825
[root@pvcent107 build]# jobs
[1]+  Running                 cp -i -r testLargeFile largeFile &
[root@pvcent107 build]# disown -h %1
[root@pvcent107 build]# ps -ef |grep largeFile
root      4825   968  1 09:46 pts/4    00:00:00 cp -i -r testLargeFile largeFile
root      4853   968  0 09:46 pts/4    00:00:00 grep largeFile
[root@pvcent107 build]# logout   


disown 示例2(如果提交命令时未使用“&”将命令放入后台运行,可使用 CTRL-z 和“bg”将其放入后台,再使用“disown”)
                
[root@pvcent107 build]# cp -r testLargeFile largeFile2

[1]+  Stopped                 cp -i -r testLargeFile largeFile2
[root@pvcent107 build]# bg %1
[1]+ cp -i -r testLargeFile largeFile2 &
[root@pvcent107 build]# jobs
[1]+  Running                 cp -i -r testLargeFile largeFile2 &
[root@pvcent107 build]# disown -h %1
[root@pvcent107 build]# ps -ef |grep largeFile2
root      5790  5577  1 10:04 pts/3    00:00:00 cp -i -r testLargeFile largeFile2
root      5824  5577  0 10:05 pts/3    00:00:00 grep largeFile2
[root@pvcent107 build]#   

我们已经知道了如何让进程免受 HUP 信号的影响,但是如果有大量这种命令需要在稳定的后台里运行,如何避免对每条命令都做这样的操作呢?
此时最方便的方法就是 screen 了。简单的说,screen 提供了 ANSI/VT100 的终端模拟器,使它能够在一个真实终端下运行多个全屏的伪终端。screen 的参数很多,具有很强大的功能,我们在此仅介绍其常用功能以及简要分析一下为什么使用 screen 能够避免 HUP 信号的影响。我们先看一下 screen 的帮助信息:
SCREEN(1)                                                           SCREEN(1)

NAME
       screen - screen manager with VT100/ANSI terminal emulation

SYNOPSIS
       screen [ -options ] [ cmd [ args ] ]
       screen -r [[pid.]tty[.host]]
       screen -r sessionowner/[[pid.]tty[.host]]

DESCRIPTION
       Screen  is  a  full-screen  window manager that multiplexes a physical
       terminal between several  processes  (typically  interactive  shells).
       Each  virtual  terminal provides the functions of a DEC VT100 terminal
       and, in addition, several control functions from the  ISO  6429  (ECMA
       48,  ANSI  X3.64)  and ISO 2022 standards (e.g. insert/delete line and
       support for multiple character sets).  There is a  scrollback  history
       buffer  for  each virtual terminal and a copy-and-paste mechanism that
       allows moving text regions between windows. 

使用 screen 很方便,有以下几个常用选项:
  • screen -dmS session name 来建立一个处于断开模式下的会话(并指定其会话名)。
  • screen -list 来列出所有会话。
  • screen -r session name 来重新连接指定会话。
  • 用快捷键CTRL-a d 来暂时断开当前会话。

screen 示例
                
[root@pvcent107 ~]# screen -dmS Urumchi
[root@pvcent107 ~]# screen -list
There is a screen on:
        12842.Urumchi   (Detached)
1 Socket in /tmp/screens/S-root.

[root@pvcent107 ~]# screen -r Urumchi  

当我们用“-r”连接到 screen 会话后,我们就可以在这个伪终端里面为所欲为,再也不用担心 HUP 信号会对我们的进程造成影响,也不用给每个命令前都加上“nohup”或者“setsid”了。这是为什么呢?让我来看一下下面两个例子吧。

1. 未使用 screen 时新进程的进程树
                
[root@pvcent107 ~]# ping www.google.com &
[1] 9499
[root@pvcent107 ~]# pstree -H 9499
init─┬─Xvnc
     ├─acpid
     ├─atd
     ├─2*[sendmail] 
     ├─sshd─┬─sshd───bash───pstree
     │       └─sshd───bash───ping
            

我们可以看出,未使用 screen 时我们所处的 bash 是 sshd 的子进程,当 ssh 断开连接时,HUP 信号自然会影响到它下面的所有子进程(包括我们新建立的 ping 进程)。

2. 使用了 screen 后新进程的进程树
                
[root@pvcent107 ~]# screen -r Urumchi
[root@pvcent107 ~]# ping www.ibm.com &
[1] 9488
[root@pvcent107 ~]# pstree -H 9488
init─┬─Xvnc
     ├─acpid
     ├─atd
     ├─screen───bash───ping
     ├─2*[sendmail] 

而使用了 screen 后就不同了,此时 bash 是 screen 的子进程,而 screen 是 init(PID为1)的子进程。那么当 ssh 断开连接时,HUP 信号自然不会影响到 screen 下面的子进程了。
现在几种方法已经介绍完毕,我们可以根据不同的场景来选择不同的方案。nohup/setsid 无疑是临时需要时最方便的方法,disown 能帮助我们来事后补救当前已经在运行了的作业,而 screen 则是在大批量操作时不二的选择了。

申毅,IBM 中国软件开发中心 WebSphere Portal 部门软件工程师。

2013年8月8日星期四

linux监控程序-程序自动重启方法

1)exec函数把当前进程替换为一个新的进程,新进程由path或file参数指定。可以使用exec函数将程序的执行从一个程序切换到另一个程序;
2)fork函数是创建一个新的进程,在进程表中创建一个新的表项,而创建者(即父进程)按原来的流程继续执行,子进程执行自己的控制流程;
3)wait 当fork启动一个子进程时,子进程就有了它自己的生命周期并将独立运行,我们可以在父进程中调用wait函数让父进程等待子进程的结束;
相信介绍到这里,读者已经能够想到解决方法了:1)首先使用fork系统调用,创建子进程,2)在子进程中使用exec函数,执行需要自动重启的程序,3) 在父进程中执行wait等待子进程的结束,然后重新创建一个新的子进程。

点击(此处)折叠或打开
  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <errno.h>
  4. #include <string.h>
  5. #include <sys/types.h>
  6. #include <sys/wait.h>
  7. #include <stdlib.h>
  8.  
  9. int
  10. main(int argc, char **argv)
  11. {
  12.     int ret, i, status;
  13.     char *child_argv[100] = {0};
  14.     pid_t pid;
  15.     if (argc < 2) {
  16.  
  17.         fprintf(stderr, "Usage:%s <exe_path> <args...>n", argv[0]);
  18.         return -1;
  19.     }
  20.     for (= 1; i < argc; ++i) {
  21.         child_argv[i-1] = (char *)malloc(strlen(argv[i])+1);
  22.         strncpy(child_argv[i-1], argv[i], strlen(argv[i]));
  23.         child_argv[i-1][strlen(argv[i])] = '0';
  24.     }
  25.     while(1){
  26.  
  27.         pid = fork(); 
  28.         if (pid == -1) {
  29.             fprintf(stderr, "fork() error.errno:%d error:%sn", errno, strerror(errno));
  30.             break;
  31.         }
  32.         if (pid == 0) {
  33.             ret = execv(child_argv[0], (char **)child_argv);
  34.             //ret = execl(child_argv[0], "portmap", NULL, 0);
  35.             if (ret < 0) {
  36.                 fprintf(stderr, "execv ret:%d errno:%d error:%sn", ret, errno, strerror(errno));
  37.                 continue;
  38.             }
  39.             exit(0);
  40.         }
  41.  
  42.         if (pid > 0) {
  43.             pid = wait(&status);
  44.  
  45.             fprintf(stdout, "wait return");
  46.         }
  47.  
  48.     }
  49.  
  50.  
  51.     return 0;
  52. }

shell脚本方式的代码如下:

点击(此处)折叠或打开
  1. # 函数: CheckProcess
  2. # 功能: 检查一个进程是否存在
  3. # 参数: $1 --- 要检查的进程名称
  4. # 返回: 如果存在返回0, 否则返回1.
  5. #------------------------------------------------------------------------------
  6. CheckProcess()
  7. {
  8.   # 检查输入的参数是否有效
  9.   if [ "$1" = "" ];
  10.   then
  11.     return 1
  12.   fi
  13.  
  14.   #$PROCESS_NUM获取指定进程名的数目,为1返回0,表示正常,不为1返回1,表示有错误,需要重新启动
  15.   PROCESS_NUM=`ps -ef | grep "$1" | grep -"grep" | wc -l` 
  16.   if [ $PROCESS_NUM -eq 1 ];
  17.   then
  18.     return 0
  19.   else
  20.     return 1
  21.   fi
  22. }
  23.  
  24.  
  25. # 检查test实例是否已经存在
  26. while [ 1 ] ; do
  27.  CheckProcess "test"
  28.  CheckQQ_RET=$?
  29.  if [ $CheckQQ_RET -eq 1 ];
  30.  then
  31.  
  32. # 杀死所有test进程,可换任意你需要执行的操作
  33.  
  34.  
  35.   killall -9 test
  36.   exec ./test & 
  37.  fi
  38.  sleep 1
  39. done