1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
|
diff --git a/include/refcount.h b/include/refcount.h
index 785b052..533fdfe 100644
--- a/include/refcount.h
+++ b/include/refcount.h
@@ -31,10 +31,11 @@
/* An opaque type. You must not access these values directly. */
typedef unsigned int refcount_t;
-/* Initialize REF with REFERENCES. */
+/* Initialize REF with REFERENCES. REFERENCES must not be zero. */
static inline void
refcount_init (refcount_t *ref, unsigned int references)
{
+ assert (references > 0 || !"references must not be zero!");
*ref = references;
}
@@ -47,6 +48,7 @@ refcount_ref (refcount_t *ref)
unsigned int r;
r = __atomic_add_fetch (ref, 1, __ATOMIC_RELAXED);
assert (r != UINT_MAX || !"refcount overflowed!");
+ assert (r != 1 || !"refcount detected use after free!");
return r;
}
@@ -101,10 +103,12 @@ union _references {
uint64_t value;
};
-/* Initialize REF with HARD and WEAK references. */
+/* Initialize REF with HARD and WEAK references. HARD and WEAK must
+ not both be zero. */
static inline void
refcounts_init (refcounts_t *ref, uint32_t hard, uint32_t weak)
{
+ assert ((hard != 0 || weak != 0) || !"references must not both be zero!");
ref->references = (struct references) { .hard = hard, .weak = weak };
}
@@ -119,6 +123,8 @@ refcounts_ref (refcounts_t *ref, struct references *result)
union _references r;
r.value = __atomic_add_fetch (&ref->value, op.value, __ATOMIC_RELAXED);
assert (r.references.hard != UINT32_MAX || !"refcount overflowed!");
+ assert (! (r.references.hard == 1 && r.references.weak == 0)
+ || !"refcount detected use after free!");
if (result)
*result = r.references;
}
@@ -208,6 +214,8 @@ refcounts_ref_weak (refcounts_t *ref, struct references *result)
union _references r;
r.value = __atomic_add_fetch (&ref->value, op.value, __ATOMIC_RELAXED);
assert (r.references.weak != UINT32_MAX || !"refcount overflowed!");
+ assert (! (r.references.hard == 0 && r.references.weak == 1)
+ || !"refcount detected use after free!");
if (result)
*result = r.references;
}
diff --git a/libdiskfs/diskfs.h b/libdiskfs/diskfs.h
index e328527..e59ba99 100644
--- a/libdiskfs/diskfs.h
+++ b/libdiskfs/diskfs.h
@@ -820,12 +820,12 @@ diskfs_create_node (struct node *dir, const char *name, mode_t mode,
struct dirstat *ds);
/* Create and return a protid for an existing peropen PO in CRED,
- referring to user USER. */
+ referring to user USER. On success, consume a reference to PO. */
error_t diskfs_create_protid (struct peropen *po, struct iouser *user,
struct protid **cred);
/* Build and return in CRED a protid which has no user identification, for
- peropen PO. */
+ peropen PO. On success, consume a reference to PO. */
error_t diskfs_start_protid (struct peropen *po, struct protid **cred);
/* Finish building protid CRED started with diskfs_start_protid;
diff --git a/libdiskfs/io-duplicate.c b/libdiskfs/io-duplicate.c
index 45c4df5..a2e568b 100644
--- a/libdiskfs/io-duplicate.c
+++ b/libdiskfs/io-duplicate.c
@@ -32,6 +32,7 @@ diskfs_S_io_duplicate (struct protid *cred,
pthread_mutex_lock (&cred->po->np->lock);
+ refcount_ref (&cred->po->refcnt);
err = diskfs_create_protid (cred->po, cred->user, &newpi);
if (! err)
{
@@ -39,6 +40,8 @@ diskfs_S_io_duplicate (struct protid *cred,
*portpoly = MACH_MSG_TYPE_MAKE_SEND;
ports_port_deref (newpi);
}
+ else
+ refcount_deref (&cred->po->refcnt);
pthread_mutex_unlock (&cred->po->np->lock);
diff --git a/libdiskfs/io-reauthenticate.c b/libdiskfs/io-reauthenticate.c
index 69d78bc..649315f 100644
--- a/libdiskfs/io-reauthenticate.c
+++ b/libdiskfs/io-reauthenticate.c
@@ -35,11 +35,13 @@ diskfs_S_io_reauthenticate (struct protid *cred,
are a simpleroutine, so callers won't know to restart. */
pthread_mutex_lock (&cred->po->np->lock);
+ refcount_ref (&cred->po->refcnt);
do
err = diskfs_start_protid (cred->po, &newcred);
while (err == EINTR);
if (err)
{
+ refcount_deref (&cred->po->refcnt);
pthread_mutex_unlock (&cred->po->np->lock);
return err;
}
diff --git a/libdiskfs/io-restrict-auth.c b/libdiskfs/io-restrict-auth.c
index 011aa19..80c0b20 100644
--- a/libdiskfs/io-restrict-auth.c
+++ b/libdiskfs/io-restrict-auth.c
@@ -41,6 +41,7 @@ diskfs_S_io_restrict_auth (struct protid *cred,
return err;
pthread_mutex_lock (&cred->po->np->lock);
+ refcount_ref (&cred->po->refcnt);
err = diskfs_create_protid (cred->po, user, &newpi);
if (! err)
{
@@ -48,6 +49,8 @@ diskfs_S_io_restrict_auth (struct protid *cred,
*newportpoly = MACH_MSG_TYPE_MAKE_SEND;
ports_port_deref (newpi);
}
+ else
+ refcount_deref (&cred->po->refcnt);
pthread_mutex_unlock (&cred->po->np->lock);
iohelp_free_iouser (user);
diff --git a/libdiskfs/peropen-make.c b/libdiskfs/peropen-make.c
index 6d5ca01..788b9a7 100644
--- a/libdiskfs/peropen-make.c
+++ b/libdiskfs/peropen-make.c
@@ -31,7 +31,7 @@ diskfs_make_peropen (struct node *np, int flags, struct peropen *context,
po->filepointer = 0;
po->lock_status = LOCK_UN;
- refcount_init (&po->refcnt, 0);
+ refcount_init (&po->refcnt, 1);
po->openstat = flags;
po->np = np;
po->path = NULL;
diff --git a/libdiskfs/protid-make.c b/libdiskfs/protid-make.c
index 22aaa2e..0b09299 100644
--- a/libdiskfs/protid-make.c
+++ b/libdiskfs/protid-make.c
@@ -20,7 +20,7 @@
#include <assert.h>
/* Build and return in CRED a protid which has no user identification, for
- peropen PO. */
+ peropen PO. On success, consume a reference to PO. */
error_t
diskfs_start_protid (struct peropen *po, struct protid **cred)
{
@@ -29,7 +29,7 @@ diskfs_start_protid (struct peropen *po, struct protid **cred)
sizeof (struct protid), cred);
if (! err)
{
- refcount_ref (&po->refcnt);
+ /* Consume a reference to po. */
(*cred)->po = po;
(*cred)->shared_object = MACH_PORT_NULL;
(*cred)->mapped = 0;
@@ -56,7 +56,7 @@ diskfs_finish_protid (struct protid *cred, struct iouser *user)
}
/* Create and return a protid for an existing peropen PO in CRED for
- USER. */
+ USER. On success, consume a reference to PO. */
error_t
diskfs_create_protid (struct peropen *po, struct iouser *user,
struct protid **cred)
|