Skip to content

Commit f2613d0

Browse files
author
Christian Ehrhardt
committed
cheri: clang-tidy: Check correct usage of __c_ua() vs. __c_ua_u()
In the CHERI Linux Kernel __c_ua() must be used to convert a kernel pointer to an address while __c_ua_u() must be used for user pointers. Check that this is consistently done even if the current configuration does the same thing for both.
1 parent 3bed353 commit f2613d0

File tree

9 files changed

+150
-0
lines changed

9 files changed

+150
-0
lines changed

clang-tools-extra/clang-tidy/cheri/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ add_clang_library(clangTidyCheriModule
1010
FixdriverdataCheck.cpp
1111
FixinttoptrcastCheck.cpp
1212
FixptrtoulongcastCheck.cpp
13+
FixuserptrtoaddrCheck.cpp
1314
IoctlCheck.cpp
1415
PtrtointcastCheck.cpp
1516

clang-tools-extra/clang-tidy/cheri/CheriTidyModule.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "FixdriverdataCheck.h"
1515
#include "FixinttoptrcastCheck.h"
1616
#include "FixptrtoulongcastCheck.h"
17+
#include "FixuserptrtoaddrCheck.h"
1718
#include "IoctlCheck.h"
1819
#include "PtrtointcastCheck.h"
1920

@@ -34,6 +35,8 @@ class CheriModule : public ClangTidyModule {
3435
"cheri-FixIntToPtrCast");
3536
CheckFactories.registerCheck<FixptrtoulongcastCheck>(
3637
"cheri-FixPtrToUlongCast");
38+
CheckFactories.registerCheck<FixuserptrtoaddrCheck>(
39+
"cheri-FixUserPtrToAddr");
3740
CheckFactories.registerCheck<IoctlCheck>(
3841
"cheri-Ioctl");
3942
CheckFactories.registerCheck<PtrtointcastCheck>("cheri-PtrToIntCast");

clang-tools-extra/clang-tidy/cheri/CheriUtil.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ class Util {
7171
}
7272
}
7373

74+
static bool isUserPtr(const Expr *E) {
75+
return isUserPtr(E->getType().getTypePtr());
76+
}
77+
7478
/*
7579
* Given a type of something that is or can be called find the
7680
* type of the actual function that is called as a FunctionProtoType.
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
//===--- FixuserptrtoaddrCheck.cpp - clang-tidy ---------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "CheriUtil.h"
10+
#include "FixuserptrtoaddrCheck.h"
11+
#include "clang/AST/ASTContext.h"
12+
#include "clang/ASTMatchers/ASTMatchFinder.h"
13+
14+
using namespace clang::ast_matchers;
15+
16+
namespace clang::tidy::cheri {
17+
18+
void FixuserptrtoaddrCheck::registerMatchers(MatchFinder *Finder) {
19+
// clang-format off
20+
Finder->addMatcher(
21+
callExpr(
22+
callee(
23+
functionDecl(
24+
hasName("__c_pa")
25+
)
26+
)
27+
).bind("cpa"),
28+
this
29+
);
30+
Finder->addMatcher(
31+
callExpr(
32+
callee(
33+
functionDecl(
34+
hasName("__c_pa_u")
35+
)
36+
)
37+
).bind("cpau"),
38+
this
39+
);
40+
// clang-format on
41+
}
42+
43+
void FixuserptrtoaddrCheck::check(const MatchFinder::MatchResult &Result) {
44+
const auto *Cpa = Result.Nodes.getNodeAs<CallExpr>("cpa");
45+
const auto *Cpau = Result.Nodes.getNodeAs<CallExpr>("cpau");
46+
const CallExpr *Call = Cpa ? Cpa : Cpau;
47+
48+
if (Cpa && Cpau)
49+
return;
50+
if (!Call || Call->getNumArgs() == 0)
51+
return;
52+
53+
/*
54+
* Skip the outer most implicit cast (if any) that converts to the
55+
* formal type of the function parameter.
56+
*/
57+
const Expr *Arg = Call->getArg(0);
58+
if (const auto *Cast = dyn_cast<ImplicitCastExpr>(Arg))
59+
Arg = Cast->getSubExpr();
60+
bool user = Util::isUserPtr(Arg);
61+
62+
const Expr *Callee = Call->getCallee();
63+
auto R = CharSourceRange::getTokenRange(Callee->getBeginLoc(), Callee->getEndLoc());
64+
if (user && !Cpau)
65+
{
66+
diag(Call->getExprLoc(),
67+
"CHERI: __c_pa() on user pointer. Should be __c_pa_u()")
68+
<< FixItHint::CreateReplacement(R, "__c_pa_u");
69+
}
70+
if (!user && !Cpa)
71+
{
72+
diag(Call->getExprLoc(),
73+
"CHERI: __c_pa_u() on kernel pointer. Should be __c_pa()")
74+
<< FixItHint::CreateReplacement(R, "__c_pa");
75+
}
76+
}
77+
78+
} // namespace clang::tidy::cheri
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//===--- FixuserptrtoaddrCheck.h - clang-tidy -------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CHERI_FIXUSERPTRTOADDRCHECK_H
10+
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CHERI_FIXUSERPTRTOADDRCHECK_H
11+
12+
#include "../ClangTidyCheck.h"
13+
14+
namespace clang::tidy::cheri {
15+
16+
/// In the CHERI Linux Kernel __c_ua() must be used to convert
17+
/// a kernel pointer to an address while __c_ua_u() must be used
18+
/// for user pointers. Check that this is consistently done even
19+
/// if the current configuration does the same thing for both.
20+
class FixuserptrtoaddrCheck : public ClangTidyCheck {
21+
public:
22+
FixuserptrtoaddrCheck(StringRef Name, ClangTidyContext *Context)
23+
: ClangTidyCheck(Name, Context) {}
24+
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
25+
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
26+
};
27+
28+
} // namespace clang::tidy::cheri
29+
30+
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CHERI_FIXUSERPTRTOADDRCHECK_H

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,11 @@ New checks
184184
Warn about explicit casts of pointers to a type that can only hold
185185
an address.
186186

187+
- New :doc:`cheri-FixUserPtrToAddr
188+
<clang-tidy/checks/cheri/FixUserPtrToAddr>` check.
189+
190+
Warn about incorrect use for __c_ua() vs. __c_ua_u() in the linux kernel.
191+
187192
- New :doc:`cheri-Ioctl
188193
<clang-tidy/checks/cheri/Ioctl>` check.
189194

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
.. title:: clang-tidy - cheri-FixUserPtrToAddr
2+
3+
cheri-FixUserPtrToAddr
4+
======================
5+
6+
In the CHERI Linux Kernel __c_ua() must be used to convert
7+
a kernel pointer to an address while __c_ua_u() must be used
8+
for user pointers. Check that this is consistently done even
9+
if the current configuration does the same thing for both.
10+

clang-tools-extra/docs/clang-tidy/checks/list.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ Clang-Tidy Checks
167167
`cheri-FixDriverData <cheri/FixDriverData.html>`_, "Yes"
168168
`cheri-FixIntToPtrCast <cheri/FixIntToPtrCast.html>`_, "Yes"
169169
`cheri-FixPtrToUlongCast <cheri/FixPtrToUlongCast.html>`_, "Yes"
170+
`cheri-FixUserPtrToAddr <cheri/FixUserPtrToAddr.html>`_, "Yes"
170171
`cheri-Ioctl <cheri/Ioctl.html>`_, "Yes"
171172
`cheri-PtrToIntCast <cheri/PtrToIntCast.html>`_,
172173
`clang-analyzer-core.DynamicTypePropagation <clang-analyzer/core.DynamicTypePropagation.html>`_,
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// RUN: %check_clang_tidy %s cheri-FixUserPtrToAddr %t
2+
3+
#define __user [[clang::annotate_type("user")]]
4+
5+
extern unsigned long __c_pa(const volatile void *);
6+
extern unsigned long __c_pa_u(const volatile void __user *);
7+
8+
int
9+
f(void *kp, void __user *up)
10+
{
11+
__c_pa(kp);
12+
__c_pa_u(kp);
13+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: CHERI: __c_pa_u() on kernel pointer. Should be __c_pa() [cheri-FixUserPtrToAddr]
14+
__c_pa(up);
15+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: CHERI: __c_pa() on user pointer. Should be __c_pa_u() [cheri-FixUserPtrToAddr]
16+
__c_pa_u(up);
17+
}
18+

0 commit comments

Comments
 (0)