forked from OSchip/llvm-project
android: add a close-on-exec check on pipe2()
On Android, pipe2() is better to set O_CLOEXEC flag to avoid file descriptor leakage. Patch by Jian Cai! Differential Revision: https://reviews.llvm.org/D62049 llvm-svn: 362672
This commit is contained in:
parent
5e7ca755d8
commit
3da331b456
|
|
@ -20,6 +20,7 @@
|
|||
#include "CloexecInotifyInitCheck.h"
|
||||
#include "CloexecMemfdCreateCheck.h"
|
||||
#include "CloexecOpenCheck.h"
|
||||
#include "CloexecPipe2Check.h"
|
||||
#include "CloexecSocketCheck.h"
|
||||
#include "ComparisonInTempFailureRetryCheck.h"
|
||||
|
||||
|
|
@ -49,6 +50,7 @@ public:
|
|||
CheckFactories.registerCheck<CloexecMemfdCreateCheck>(
|
||||
"android-cloexec-memfd-create");
|
||||
CheckFactories.registerCheck<CloexecOpenCheck>("android-cloexec-open");
|
||||
CheckFactories.registerCheck<CloexecPipe2Check>("android-cloexec-pipe2");
|
||||
CheckFactories.registerCheck<CloexecSocketCheck>("android-cloexec-socket");
|
||||
CheckFactories.registerCheck<ComparisonInTempFailureRetryCheck>(
|
||||
"android-comparison-in-temp-failure-retry");
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ add_clang_library(clangTidyAndroidModule
|
|||
CloexecInotifyInitCheck.cpp
|
||||
CloexecMemfdCreateCheck.cpp
|
||||
CloexecOpenCheck.cpp
|
||||
CloexecPipe2Check.cpp
|
||||
CloexecSocketCheck.cpp
|
||||
ComparisonInTempFailureRetryCheck.cpp
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
//===--- CloexecPipe2Check.cpp - clang-tidy--------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "CloexecPipe2Check.h"
|
||||
#include "../utils/ASTUtils.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/ASTMatchers/ASTMatchFinder.h"
|
||||
|
||||
using namespace clang::ast_matchers;
|
||||
|
||||
namespace clang {
|
||||
namespace tidy {
|
||||
namespace android {
|
||||
|
||||
void CloexecPipe2Check::registerMatchers(MatchFinder *Finder) {
|
||||
registerMatchersImpl(Finder,
|
||||
functionDecl(returns(isInteger()), hasName("pipe2"),
|
||||
hasParameter(0, hasType(pointsTo(isInteger()))),
|
||||
hasParameter(1, hasType(isInteger()))));
|
||||
}
|
||||
|
||||
void CloexecPipe2Check::check(const MatchFinder::MatchResult &Result) {
|
||||
insertMacroFlag(Result, /*MacroFlag=*/"O_CLOEXEC", /*ArgPos=*/1);
|
||||
}
|
||||
|
||||
} // namespace android
|
||||
} // namespace tidy
|
||||
} // namespace clang
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
//===--- CloexecPipe2Check.h - clang-tidy------------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ANDROID_CLOEXEC_PIPE2_H
|
||||
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ANDROID_CLOEXEC_PIPE2_H
|
||||
|
||||
#include "CloexecCheck.h"
|
||||
|
||||
namespace clang {
|
||||
namespace tidy {
|
||||
namespace android {
|
||||
|
||||
/// Finds code that uses pipe2() without using the O_CLOEXEC flag.
|
||||
///
|
||||
/// For the user-facing documentation see:
|
||||
/// http://clang.llvm.org/extra/clang-tidy/checks/android-cloexec-pipe2.html
|
||||
class CloexecPipe2Check : public CloexecCheck {
|
||||
public:
|
||||
CloexecPipe2Check(StringRef Name, ClangTidyContext *Context)
|
||||
: CloexecCheck(Name, Context) {}
|
||||
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
|
||||
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
|
||||
};
|
||||
|
||||
} // namespace android
|
||||
} // namespace tidy
|
||||
} // namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ANDROID_CLOEXEC_PIPE2_H
|
||||
|
|
@ -101,6 +101,11 @@ Improvements to clang-tidy
|
|||
Finds and fixes ``absl::Time`` subtraction expressions to do subtraction
|
||||
in the Time domain instead of the numeric domain.
|
||||
|
||||
- New :doc:`android-cloexec-pipe2
|
||||
<clang-tidy/checks/android-cloexec-pipe2>` check.
|
||||
|
||||
This checks ensures that ``pipe2()`` is called with the O_CLOEXEC flag.
|
||||
|
||||
- New :doc:`bugprone-unhandled-self-assignment
|
||||
<clang-tidy/checks/bugprone-unhandled-self-assignment>` check.
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
.. title:: clang-tidy - android-cloexec-pipe2
|
||||
|
||||
android-cloexec-pipe2
|
||||
=====================
|
||||
|
||||
This checks ensures that pipe2() is called with the O_CLOEXEC flag. The check also
|
||||
adds the O_CLOEXEC flag that marks the file descriptor to be closed in child processes.
|
||||
Without this flag a sensitive file descriptor can be leaked to a child process,
|
||||
potentially into a lower-privileged SELinux domain.
|
||||
|
||||
Examples:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
pipe2(pipefd, O_NONBLOCK);
|
||||
|
||||
Suggested replacement:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
pipe2(pipefd, O_NONBLOCK | O_CLOEXEC);
|
||||
|
|
@ -32,6 +32,7 @@ Clang-Tidy Checks
|
|||
android-cloexec-inotify-init1
|
||||
android-cloexec-memfd-create
|
||||
android-cloexec-open
|
||||
android-cloexec-pipe2
|
||||
android-cloexec-socket
|
||||
android-comparison-in-temp-failure-retry
|
||||
boost-use-to-string
|
||||
|
|
|
|||
|
|
@ -0,0 +1,68 @@
|
|||
// RUN: %check_clang_tidy %s android-cloexec-pipe2 %t
|
||||
|
||||
#define O_NONBLOCK 1
|
||||
#define __O_CLOEXEC 3
|
||||
#define O_CLOEXEC __O_CLOEXEC
|
||||
#define TEMP_FAILURE_RETRY(exp) \
|
||||
({ \
|
||||
int _rc; \
|
||||
do { \
|
||||
_rc = (exp); \
|
||||
} while (_rc == -1); \
|
||||
})
|
||||
#define NULL 0
|
||||
|
||||
extern "C" int pipe2(int pipefd[2], int flags);
|
||||
|
||||
void warning() {
|
||||
int pipefd[2];
|
||||
pipe2(pipefd, O_NONBLOCK);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: 'pipe2'
|
||||
// CHECK-FIXES: pipe2(pipefd, O_NONBLOCK | O_CLOEXEC);
|
||||
TEMP_FAILURE_RETRY(pipe2(pipefd, O_NONBLOCK));
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:46: warning: 'pipe2'
|
||||
// CHECK-FIXES: TEMP_FAILURE_RETRY(pipe2(pipefd, O_NONBLOCK | O_CLOEXEC));
|
||||
}
|
||||
|
||||
void warningInMacroArugment() {
|
||||
int pipefd[2];
|
||||
pipe2(pipefd, 3);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: 'pipe2'
|
||||
// CHECK-FIXES: pipe2(pipefd, 3 | O_CLOEXEC);
|
||||
TEMP_FAILURE_RETRY(pipe2(pipefd, 3));
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:37: warning: 'pipe2'
|
||||
// CHECK-FIXES: TEMP_FAILURE_RETRY(pipe2(pipefd, 3 | O_CLOEXEC));
|
||||
|
||||
int flag = O_NONBLOCK;
|
||||
pipe2(pipefd, flag);
|
||||
TEMP_FAILURE_RETRY(pipe2(pipefd, flag));
|
||||
}
|
||||
|
||||
namespace i {
|
||||
int pipe2(int pipefd[2], int flags);
|
||||
|
||||
void noWarning() {
|
||||
int pipefd[2];
|
||||
pipe2(pipefd, O_NONBLOCK);
|
||||
TEMP_FAILURE_RETRY(pipe2(pipefd, O_NONBLOCK));
|
||||
}
|
||||
|
||||
} // namespace i
|
||||
|
||||
void noWarning() {
|
||||
int pipefd[2];
|
||||
pipe2(pipefd, O_CLOEXEC);
|
||||
TEMP_FAILURE_RETRY(pipe2(pipefd, O_CLOEXEC));
|
||||
pipe2(pipefd, O_NONBLOCK | O_CLOEXEC);
|
||||
TEMP_FAILURE_RETRY(pipe2(pipefd, O_NONBLOCK | O_CLOEXEC));
|
||||
}
|
||||
|
||||
class G {
|
||||
public:
|
||||
int pipe2(int pipefd[2], int flags);
|
||||
void noWarning() {
|
||||
int pipefd[2];
|
||||
pipe2(pipefd, O_NONBLOCK);
|
||||
TEMP_FAILURE_RETRY(pipe2(pipefd, O_NONBLOCK));
|
||||
}
|
||||
};
|
||||
Loading…
Reference in New Issue