Skip to content

Commit 1180b4c

Browse files
committed
apparmor: fix dangling symlinks to policy rawdata after replacement
When policy replacement occurs the symlinks in the profile directory need to be updated to point to the new rawdata, otherwise once the old rawdata is removed the symlink becomes broken. Fix this by dynamically generating the symlink everytime it is read. These links are used enough that their value needs to be cached and this way we can avoid needing locking to read and update the link value. Fixes: a481f4d ("apparmor: add custom apparmorfs that will be used by policy namespace files") BugLink: http://bugs.launchpad.net/bugs/1755563 Signed-off-by: John Johansen <john.johansen@canonical.com>
1 parent d53c9f4 commit 1180b4c

File tree

1 file changed

+95
-31
lines changed

1 file changed

+95
-31
lines changed

security/apparmor/apparmorfs.c

Lines changed: 95 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,7 @@ static struct dentry *aafs_create_dir(const char *name, struct dentry *parent)
310310
* @name: name of dentry to create
311311
* @parent: parent directory for this dentry
312312
* @target: if symlink, symlink target string
313+
* @private: private data
313314
* @iops: struct of inode_operations that should be used
314315
*
315316
* If @target parameter is %NULL, then the @iops parameter needs to be
@@ -318,17 +319,17 @@ static struct dentry *aafs_create_dir(const char *name, struct dentry *parent)
318319
static struct dentry *aafs_create_symlink(const char *name,
319320
struct dentry *parent,
320321
const char *target,
322+
void *private,
321323
const struct inode_operations *iops)
322324
{
323325
struct dentry *dent;
324326
char *link = NULL;
325327

326328
if (target) {
327-
link = kstrdup(target, GFP_KERNEL);
328329
if (!link)
329330
return ERR_PTR(-ENOMEM);
330331
}
331-
dent = aafs_create(name, S_IFLNK | 0444, parent, NULL, link, NULL,
332+
dent = aafs_create(name, S_IFLNK | 0444, parent, private, link, NULL,
332333
iops);
333334
if (IS_ERR(dent))
334335
kfree(link);
@@ -1479,26 +1480,95 @@ static int profile_depth(struct aa_profile *profile)
14791480
return depth;
14801481
}
14811482

1482-
static int gen_symlink_name(char *buffer, size_t bsize, int depth,
1483-
const char *dirname, const char *fname)
1483+
static char *gen_symlink_name(int depth, const char *dirname, const char *fname)
14841484
{
1485+
char *buffer, *s;
14851486
int error;
1487+
int size = depth * 6 + strlen(dirname) + strlen(fname) + 11;
1488+
1489+
s = buffer = kmalloc(size, GFP_KERNEL);
1490+
if (!buffer)
1491+
return ERR_PTR(-ENOMEM);
14861492

14871493
for (; depth > 0; depth--) {
1488-
if (bsize < 7)
1489-
return -ENAMETOOLONG;
1490-
strcpy(buffer, "../../");
1491-
buffer += 6;
1492-
bsize -= 6;
1494+
strcpy(s, "../../");
1495+
s += 6;
1496+
size -= 6;
14931497
}
14941498

1495-
error = snprintf(buffer, bsize, "raw_data/%s/%s", dirname, fname);
1496-
if (error >= bsize || error < 0)
1497-
return -ENAMETOOLONG;
1499+
error = snprintf(s, size, "raw_data/%s/%s", dirname, fname);
1500+
if (error >= size || error < 0)
1501+
return ERR_PTR(-ENAMETOOLONG);
14981502

1499-
return 0;
1503+
return buffer;
1504+
}
1505+
1506+
static void rawdata_link_cb(void *arg)
1507+
{
1508+
kfree(arg);
1509+
}
1510+
1511+
static const char *rawdata_get_link_base(struct dentry *dentry,
1512+
struct inode *inode,
1513+
struct delayed_call *done,
1514+
const char *name)
1515+
{
1516+
struct aa_proxy *proxy = inode->i_private;
1517+
struct aa_label *label;
1518+
struct aa_profile *profile;
1519+
char *target;
1520+
int depth;
1521+
1522+
if (!dentry)
1523+
return ERR_PTR(-ECHILD);
1524+
1525+
label = aa_get_label_rcu(&proxy->label);
1526+
profile = labels_profile(label);
1527+
depth = profile_depth(profile);
1528+
target = gen_symlink_name(depth, profile->rawdata->name, name);
1529+
aa_put_label(label);
1530+
1531+
if (IS_ERR(target))
1532+
return target;
1533+
1534+
set_delayed_call(done, rawdata_link_cb, target);
1535+
1536+
return target;
15001537
}
15011538

1539+
static const char *rawdata_get_link_sha1(struct dentry *dentry,
1540+
struct inode *inode,
1541+
struct delayed_call *done)
1542+
{
1543+
return rawdata_get_link_base(dentry, inode, done, "sha1");
1544+
}
1545+
1546+
static const char *rawdata_get_link_abi(struct dentry *dentry,
1547+
struct inode *inode,
1548+
struct delayed_call *done)
1549+
{
1550+
return rawdata_get_link_base(dentry, inode, done, "abi");
1551+
}
1552+
1553+
static const char *rawdata_get_link_data(struct dentry *dentry,
1554+
struct inode *inode,
1555+
struct delayed_call *done)
1556+
{
1557+
return rawdata_get_link_base(dentry, inode, done, "raw_data");
1558+
}
1559+
1560+
static const struct inode_operations rawdata_link_sha1_iops = {
1561+
.get_link = rawdata_get_link_sha1,
1562+
};
1563+
1564+
static const struct inode_operations rawdata_link_abi_iops = {
1565+
.get_link = rawdata_get_link_abi,
1566+
};
1567+
static const struct inode_operations rawdata_link_data_iops = {
1568+
.get_link = rawdata_get_link_data,
1569+
};
1570+
1571+
15021572
/*
15031573
* Requires: @profile->ns->lock held
15041574
*/
@@ -1569,34 +1639,28 @@ int __aafs_profile_mkdir(struct aa_profile *profile, struct dentry *parent)
15691639
}
15701640

15711641
if (profile->rawdata) {
1572-
char target[64];
1573-
int depth = profile_depth(profile);
1574-
1575-
error = gen_symlink_name(target, sizeof(target), depth,
1576-
profile->rawdata->name, "sha1");
1577-
if (error < 0)
1578-
goto fail2;
1579-
dent = aafs_create_symlink("raw_sha1", dir, target, NULL);
1642+
dent = aafs_create_symlink("raw_sha1", dir, NULL,
1643+
profile->label.proxy,
1644+
&rawdata_link_sha1_iops);
15801645
if (IS_ERR(dent))
15811646
goto fail;
1647+
aa_get_proxy(profile->label.proxy);
15821648
profile->dents[AAFS_PROF_RAW_HASH] = dent;
15831649

1584-
error = gen_symlink_name(target, sizeof(target), depth,
1585-
profile->rawdata->name, "abi");
1586-
if (error < 0)
1587-
goto fail2;
1588-
dent = aafs_create_symlink("raw_abi", dir, target, NULL);
1650+
dent = aafs_create_symlink("raw_abi", dir, NULL,
1651+
profile->label.proxy,
1652+
&rawdata_link_abi_iops);
15891653
if (IS_ERR(dent))
15901654
goto fail;
1655+
aa_get_proxy(profile->label.proxy);
15911656
profile->dents[AAFS_PROF_RAW_ABI] = dent;
15921657

1593-
error = gen_symlink_name(target, sizeof(target), depth,
1594-
profile->rawdata->name, "raw_data");
1595-
if (error < 0)
1596-
goto fail2;
1597-
dent = aafs_create_symlink("raw_data", dir, target, NULL);
1658+
dent = aafs_create_symlink("raw_data", dir, NULL,
1659+
profile->label.proxy,
1660+
&rawdata_link_data_iops);
15981661
if (IS_ERR(dent))
15991662
goto fail;
1663+
aa_get_proxy(profile->label.proxy);
16001664
profile->dents[AAFS_PROF_RAW_DATA] = dent;
16011665
}
16021666

0 commit comments

Comments
 (0)